Проверьте, выводит ли команда пустую строку

Как я могу проверить, выводит ли команда пустую строку?

Ранее вопрос задавался вопросом, есть ли файлы в каталоге. Следующий код достигает этого, но см . Ответ rsp для лучшего решения.


Пустой выход

Команды не возвращают значения – они выводят их. Вы можете записать этот вывод, используя команду substitution ; например $(ls -A) . Вы можете проверить непустую строку в Bash следующим образом:

 if [[ $(ls -A) ]]; then echo "there are files" else echo "no files found" fi 

Обратите внимание, что я использовал -A а не -a , поскольку он опускает символические текущие ( . ) И родительские ( .. ) записи каталога.

Примечание. Как отмечено в комментариях, подстановка команд не фиксирует завершающие символы новой строки . Поэтому, если команда выводит только новые строки, подстановка ничего не запишет, и тест вернет false. Хотя это маловероятно, это возможно в приведенном выше примере, поскольку одна новая строка является допустимым именем файла! Дополнительная информация в этом ответе .


Код выхода

Если вы хотите проверить, что команда выполнена успешно, вы можете проверить $? , который содержит код выхода последней команды (ноль для успеха, отличное от нуля для отказа). Например:

 files=$(ls -A) if [[ $? != 0 ]]; then echo "Command failed." elif [[ $files ]]; then echo "Files found." else echo "No files found." fi 

Больше информации здесь .

TL; DR

if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then ...; fi

Благодаря netj для предложения улучшить мой оригинал:
if [[ $(ls -A | wc -c) -ne 0 ]]; then ...; fi


Это старый вопрос, но я вижу по крайней мере две вещи, которые нуждаются в улучшении или, по крайней мере, в некоторых разъяснениях.

Первая проблема

Первая проблема, которую я вижу, заключается в том, что большинство приведенных здесь примеров просто не работают . Они используют команды ls -al и ls -Al – оба из которых выводят непустые строки в пустые каталоги. В этих примерах всегда сообщается, что есть файлы, даже если их нет .

По этой причине вы должны использовать только ls -A Почему кто-то хочет использовать ключ -l что означает «использовать длинный формат списка», когда все, что вам нужно, это тест, если есть какой-либо вывод или нет?

Поэтому большинство ответов здесь просто неверны.

Вторая проблема

Вторая проблема заключается в том, что, хотя некоторые ответы работают нормально (те, которые не используют ls -al или ls -Al но ls -A вместо этого), они все делают примерно так:

  1. выполнить команду
  2. буферировать весь его вывод в ОЗУ
  3. конвертировать вывод в огромную однострочную строку
  4. сравните эту строку с пустой строкой

Вместо этого я бы предложил:

  1. выполнить команду
  2. подсчитывать символы на своем выходе, не сохраняя их
    • или даже лучше – подсчитайте число максимально 1 символа, using head -c1
      (спасибо netj за публикацию этой идеи в комментариях ниже)
  3. сравните это число с нулем

Так, например, вместо:

 if [[ $(ls -A) ]] 

Я хотел бы использовать:

 if [[ $(ls -A | wc -c) -ne 0 ]] # or: if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]] 

Вместо:

 if [ -z "$(ls -lA)" ] 

Я хотел бы использовать:

 if [ $(ls -lA | wc -c) -eq 0 ] # or: if [ $(ls -lA | head -c1 | wc -c) -eq 0 ] 

и так далее.

Для небольших выходов это может быть не проблема, но для больших выходов разница может быть значительной:

 $ time [ -z "$(seq 1 10000000)" ] real 0m2.703s user 0m2.485s sys 0m0.347s 

Сравните это с:

 $ time [ $(seq 1 10000000 | wc -c) -eq 0 ] real 0m0.128s user 0m0.081s sys 0m0.105s 

И еще лучше:

 $ time [ $(seq 1 10000000 | head -c1 | wc -c) -eq 0 ] real 0m0.004s user 0m0.000s sys 0m0.007s 

Полный пример

Обновленный пример из ответа Уилла Вузента:

 if [[ $(ls -A | wc -c) -ne 0 ]]; then echo "there are files" else echo "no files found" fi 

Обновлено после предложений netj :

 if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then echo "there are files" else echo "no files found" fi 

Отбрасывание пробелов

Если команда, которую вы тестируете, может выводить некоторые пробелы, которые вы хотите рассматривать как пустую строку, вместо:

 | wc -c 

вы можете использовать:

 | tr -d ' \n\r\t ' | wc -c 

или с head -c1 :

 | tr -d ' \n\r\t ' | head -c1 | wc -c 

или что-то типа того.

Резюме

  1. Сначала используйте команду, которая работает .

  2. Во-вторых, избегайте ненужного хранения в ОЗУ и обработки потенциально огромных данных.

В ответе не указывалось, что выход всегда мал, поэтому необходимо учитывать возможность большой производительности.

 if [ -z "$(ls -lA)" ]; then echo "no files found" else echo "There are files" fi 

Это запустит команду и проверит, имеет ли возвращаемый вывод (строка) нулевую длину. Возможно, вы захотите проверить страницы руководства «test» для других флагов.

Используйте «» вокруг аргумента, который проверяется, иначе пустые результаты приведут к синтаксической ошибке, поскольку нет второго аргумента (для проверки)!

Обратите внимание: ls -la всегда возвращается . и .. поэтому использование этого не будет работать, см. страницы руководства ls . Кроме того, хотя это может показаться удобным и легким, я предполагаю, что он легко сломается. Написание небольшого скрипта / приложения, которое возвращает 0 или 1 в зависимости от результата, намного надежнее!

Для тех, кто хочет элегантное, независимое от bash решение (на самом деле должно работать в других современных shellх) и тех, кто любит использовать однострочники для быстрых задач. Вот так!

 ls | grep . && echo 'files found' || echo 'files not found' 

(обратите внимание на один из упомянутых комментариев: ls -al и на самом деле, просто -l и -a все вернут что-то, поэтому в моем ответе я использую простые ls

Как заметил Джон Лин, ls -al всегда будет выводить (для . И .. ). Вы хотите, чтобы ls -Al избежал этих двух каталогов.

Вы можете, например, поместить вывод команды в переменную оболочки:

 v=$(ls -Al) 

Более старые, неединичные, обозначения

 v=`ls -Al` 

но я предпочитаю вложенную нотацию $()

Вы можете проверить, не является ли эта переменная

 if [ -n "$v" ]; then echo there are files else echo no files fi 

И вы можете комбинировать оба, как if [ -n "$(ls -Al)" ]; then if [ -n "$(ls -Al)" ]; then

Справочное руководство Bash

6.4 Условные выражения Bash

 -z string True if the length of string is zero. -n string string True if the length of string is non-zero. 

Вы можете использовать сокращенную версию:

 if [[ $(ls -A) ]]; then echo "there are files" else echo "no files found" fi 

Я предполагаю, что вы хотите получить команду ls -al , поэтому в bash у вас будет что-то вроде:

 LS=`ls -la` if [ -n "$LS" ]; then echo "there are files" else echo "no files found" fi 

Вот решение для более экстремальных случаев:

 if [ `command | head -c1 | wc -c` -gt 0 ]; then ...; fi 

Это будет работать

  • для всех оболочек Борна;
  • если выход команды равен нулю;
  • эффективно независимо от размера выпуска;

Однако,

  • команда или ее subprocessы будут убиты, как только что-нибудь выйдет.

Вот альтернативный подход, который записывает std-out и std-err некоторой команды в временный файл, а затем проверяет, пуст ли этот файл. Преимущество такого подхода заключается в том, что он захватывает оба выхода и не использует суб-оболочки или каналы. Эти последние аспекты важны, потому что они могут помешать захвату выходов на выходе bash (например, здесь )

 tmpfile=$(mktemp) some-command &> "$tmpfile" if [[ $? != 0 ]]; then echo "Command failed" elif [[ -s "$tmpfile" ]]; then echo "Command generated output" else echo "Command has no output" fi rm -f "$tmpfile" 

Иногда вы хотите сохранить вывод, если он не пуст, передать его другой команде. Если это так, вы можете использовать что-то вроде

 list=`grep -l "MY_DESIRED_STRING" *.log ` if [ $? -eq 0 ] then /bin/rm $list fi 

Таким образом, команда rm не будет висеть, если список пуст.

Все ответы, которые даны до сих пор, касаются команд, которые завершают и выводят непустую строку.

Большинство из них нарушаются следующими чувствами:

  • Они не работают правильно с командами, выводящими только новые строки;
  • начиная с Bash≥4.4, большинство будет спамить стандартную ошибку, если команда выводит пустые байты (поскольку они используют подстановку команд);
  • большинство из них будет перекрывать полный выходной stream, поэтому дождитесь завершения команды перед ответом. Некоторые команды никогда не заканчиваются (попробуйте, например, yes ).

Чтобы исправить все эти проблемы и эффективно ответить на следующий вопрос,

Как я могу проверить, выводит ли команда пустую строку?

вы можете использовать:

 if read -n1 -d '' < <(command_here); then echo "Command outputs something" else echo "Command doesn't output anything" fi 

Вы также можете добавить некоторый тайм-аут, чтобы проверить, выводит ли команда непустую строку в течение заданного времени, используя параметр read -s -t . Например, в течение 2,5-секундного таймаута:

 if read -t2.5 -n1 -d '' < <(command_here); then echo "Command outputs something" else echo "Command doesn't output anything" fi 

Примечание. Если вы считаете, что вам нужно определить, выводит ли команда непустую строку, вы, скорее всего, имеете проблему XY.

  • Удалить строки в текстовом файле, который содержит определенную строку
  • $ {1: + "$ @"} в / bin / sh
  • как исправить проблему «Command / bin / sh failed with exit code 1» в iphone
  • Как добавить вывод в конец текстового файла в сценарии оболочки / bash
  • Модуль Ansible Command говорит, что '|' является незаконным персонажем
  • Многомерные массивы в Bash
  • Использование awk с переменными
  • Извлечь подстроку в Bash
  • В чем разница между командами $ (command) и `command` в программировании оболочки?
  • Как закрыть компьютер с определенным IP-адресом?
  • Проверьте, существует ли файл с шаблоном в сценарии оболочки
  • Давайте будем гением компьютера.