Команда не возвращает строку (она возвращает небольшой целочисленный код завершения, обычно 0 при успехе и 1 или 2 при ошибке), но она может вывести некоторые данные для помещения в строку.
Василий Старынкевич,
@BasileStarynkevitch - это то, что мне нужно. Я знаю, что команда возвращает код выхода. Но код выхода моей команды всегда равен 0., поэтому мне нужно контролировать вывод
Ранее задавался вопрос, как проверить, есть ли файлы в каталоге. Следующий код достигает этого, но см . Ответ rsp для лучшего решения.
Пустой вывод
Команды не возвращают значения - они выводят их. Вы можете захватить этот вывод, используя подстановку команд ; например $(ls -A). Вы можете проверить непустую строку в Bash следующим образом:
if[[ $(ls -A)]];then
echo "there are files"else
echo "no files found"fi
Обратите внимание, что я использовал -Aвместо -a, так как он пропускает символические записи каталога current ( .) и parent ( ..).
Примечание. Как указано в комментариях, подстановка команд не захватывает завершающие символы новой строки . Следовательно, если команда выводит только новые строки, подстановка ничего не захватывает, а тест возвращает false. Хотя это очень маловероятно, это возможно в приведенном выше примере, поскольку одна новая строка является допустимым именем файла! Больше информации в этом ответе .
Код выхода
Если вы хотите проверить, успешно ли выполнена команда, вы можете проверить $?, в которой содержится код завершения последней команды (ноль для успеха, ненулевое значение для сбоя). Например:
Вы можете опустить-n , так что это будет простоif [[ $(ls -A) ]]; then
пользователь
6
Этот метод выдает false для команд, которые выводят только символы новой строки.
Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
89
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 символом using head -c1 (спасибо netj за публикацию этой идеи в комментариях ниже)
сравнить это число с нулем
Так, например, вместо:
if[[ $(ls -A)]]
Я хотел бы использовать:
if[[ $(ls -A | wc -c)-ne 0]]# or:if[[ $(ls -A | head -c1 | wc -c)-ne 0]]
[[ $(... | head -c | wc -c) -gt 0 ]]или [[ -n $(... | head -c1) ]]лучше, потому wc -cчто придется использовать весь вывод команды.
нет
@netj Это очень хорошая идея. Смотрите мой обновленный ответ - я добавил ваше предложение. Большое спасибо!
RSP
Любые идеи о том, как получить выход?
fahrradflucht
Я думаю, что оригинал (без головы) лучше в общем случае. Не всегда хорошая идея убить команду, как только она начнет писать вывод!
СТК
@stk Большинство программ благополучно завершат работу после получения сигнала уничтожения.
cambunctious
40
if[-z "$(ls -lA)"];then
echo "no files found"else
echo "There are files"fi
Это запустит команду и проверит, имеет ли возвращаемый вывод (строка) нулевую длину. Возможно, вы захотите проверить справочные страницы «test» на наличие других флагов.
Используйте «» вокруг проверяемого аргумента, иначе пустые результаты приведут к синтаксической ошибке, поскольку второй аргумент (для проверки) не задан!
Обратите внимание, что ls -la всегда возвращается .и ..поэтому использование этого не будет работать, см. Справочные страницы . Кроме того, хотя это может показаться удобным и легким, я полагаю, что оно легко сломается. Написание небольшого скрипта / приложения, которое возвращает 0 или 1 в зависимости от результата, гораздо надежнее!
Вы можете предпочесть использовать $(вместо обратной цитаты, потому что $(гнездо лучше
Василий Старынкевич
Вы правы, лучше практиковать их всегда, хотя нам здесь не нужно.
Вегер
23
Для тех, кто хочет элегантное решение, не зависящее от версии bash (на самом деле должно работать в других современных оболочках), и тех, кто любит использовать однострочники для быстрых задач. Вот так!
ls | grep .&& echo 'files found'|| echo 'files not found'
(обратите внимание, как один из упомянутых комментариев, ls -alи на самом деле, просто -lи -aвсе что-то вернут, поэтому в своем ответе я использую простойls
Если вы используете grep -q ^вместо этого, символы новой строки также будут сопоставлены, и grep не будет ничего выводить на стандартный вывод. Кроме того, он выйдет, как только получит какие-либо входные данные, вместо того, чтобы ждать окончания входного потока.
mortehu
Должно начинаться с того, ls -Aесли вы хотите включить точечные файлы (или каталоги)
Это не работает: команда lsникогда не выполняется. Вы только проверяете, является ли раскрытие переменнойLS непустым.
gniourf_gniourf
1
@gniourf_gniourf - что заставляет вас так думать? Заклинание обратного удара, по общему признанию, не так красиво и гибко, как $ (), но оно работает ...
tink
-aВыключатель никогда не будет возвращать никакого содержания (то есть, он будет возвращать содержимое , есть ли файлы или нет) , так как всегда есть неявная .и ..каталоги присутствуют.
wrlee
3
Вот решение для более экстремальных случаев:
if[`command | head -c1 | wc -c`-gt 0];then...;fi
Это будет работать
для всех раковин Борна;
если команда выводит все нули;
эффективно независимо от выходного размера;
тем не мение,
команда или ее подпроцессы будут уничтожены после вывода чего-либо.
Все приведенные ответы касаются команд, которые завершают и выводят непустую строку.
Большинство из них сломаны в следующих смыслах:
Они не работают должным образом с командами, выводящими только новые строки;
начиная с Bash≥4.4, большинство из них будет содержать стандартную ошибку, если команда выводит нулевые байты (поскольку они используют подстановку команд);
большинство будет отбрасывать полный поток вывода, поэтому дождется завершения команды до ответа. Некоторые команды никогда не завершаются (попробуйте, например, yes).
Таким образом, чтобы исправить все эти проблемы и эффективно ответить на следующий вопрос,
Как я могу проверить, выводит ли команда пустую строку?
Вы можете также добавить некоторые тайм - аут для того, чтобы тест выдает ли команда не пустую строку в данный момент времени, используя read«s -tварианта. Например, в течение 2,5 секунд:
Я думаю, что этот ответ недооценивается. Я производительность тестирования некоторые из решений здесь , используя 100 итераций для каждого из 3 -х входных сценариев ( seq 1 10000000, seq 1 20и printf""). Единственный матч, который этот подход чтения не выиграл, был с -z "$(command)"подходом для пустого ввода. Даже тогда он проигрывает только на 10-15%. Кажется, они безубыточны seq 1 10. Несмотря на это, -z "$(command)"подход становится настолько медленным с ростом размера ввода, что я бы избегал использовать его для любого ввода переменного размера.
Abathur
0
Вот альтернативный подход, который записывает 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"
ifne
для этого. joeyh.name/code/moreutilsОтветы:
Ранее задавался вопрос, как проверить, есть ли файлы в каталоге. Следующий код достигает этого, но см . Ответ rsp для лучшего решения.
Пустой вывод
Команды не возвращают значения - они выводят их. Вы можете захватить этот вывод, используя подстановку команд ; например
$(ls -A)
. Вы можете проверить непустую строку в Bash следующим образом:Обратите внимание, что я использовал
-A
вместо-a
, так как он пропускает символические записи каталога current (.
) и parent (..
).Примечание. Как указано в комментариях, подстановка команд не захватывает завершающие символы новой строки . Следовательно, если команда выводит только новые строки, подстановка ничего не захватывает, а тест возвращает false. Хотя это очень маловероятно, это возможно в приведенном выше примере, поскольку одна новая строка является допустимым именем файла! Больше информации в этом ответе .
Код выхода
Если вы хотите проверить, успешно ли выполнена команда, вы можете проверить
$?
, в которой содержится код завершения последней команды (ноль для успеха, ненулевое значение для сбоя). Например:Больше информации здесь .
источник
-n
, так что это будет простоif [[ $(ls -A) ]]; then
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
вместо этого) все они делают что - то вроде этого:Вместо этого я бы предложил сделать следующее:
using head -c1
(спасибо netj за публикацию этой идеи в комментариях ниже)
Так, например, вместо:
Я хотел бы использовать:
Вместо того:
Я хотел бы использовать:
и так далее.
Для небольших выходов это может не быть проблемой, но для больших выходов разница может быть значительной:
Сравните это с:
И даже лучше:
Полный пример
Обновленный пример из ответа Уилла Воудена:
Обновляется снова после предложений от netj :
Дополнительное обновление от jakeonfire :
grep
выйдет с ошибкой, если совпадений нет. Мы можем воспользоваться этим, чтобы немного упростить синтаксис:Отбрасывание пробелов
Если команда, которую вы тестируете, может вывести некоторые пробелы, которые вы хотите рассматривать как пустую строку, то вместо:
Вы можете использовать:
или с
head -c1
:или что-то вроде того.
Резюме
Сначала используйте команду, которая работает .
Во-вторых, избегайте ненужного хранения в оперативной памяти и обработки потенциально огромных данных.
В ответе не указывалось, что выходные данные всегда малы, поэтому необходимо учитывать возможность больших выходных данных.
источник
[[ $(... | head -c | wc -c) -gt 0 ]]
или[[ -n $(... | head -c1) ]]
лучше, потомуwc -c
что придется использовать весь вывод команды.Это запустит команду и проверит, имеет ли возвращаемый вывод (строка) нулевую длину. Возможно, вы захотите проверить справочные страницы «test» на наличие других флагов.
Используйте «» вокруг проверяемого аргумента, иначе пустые результаты приведут к синтаксической ошибке, поскольку второй аргумент (для проверки) не задан!
Обратите внимание, что
ls -la
всегда возвращается.
и..
поэтому использование этого не будет работать, см. Справочные страницы . Кроме того, хотя это может показаться удобным и легким, я полагаю, что оно легко сломается. Написание небольшого скрипта / приложения, которое возвращает 0 или 1 в зависимости от результата, гораздо надежнее!источник
$(
вместо обратной цитаты, потому что$(
гнездо лучшеДля тех, кто хочет элегантное решение, не зависящее от версии bash (на самом деле должно работать в других современных оболочках), и тех, кто любит использовать однострочники для быстрых задач. Вот так!
(обратите внимание, как один из упомянутых комментариев,
ls -al
и на самом деле, просто-l
и-a
все что-то вернут, поэтому в своем ответе я использую простойls
источник
grep -q ^
вместо этого, символы новой строки также будут сопоставлены, и grep не будет ничего выводить на стандартный вывод. Кроме того, он выйдет, как только получит какие-либо входные данные, вместо того, чтобы ждать окончания входного потока.ls -A
если вы хотите включить точечные файлы (или каталоги)Справочное руководство Bash
6.4 Условные выражения Bash
Вы можете использовать сокращенную версию:
источник
string
синоним-n string
.Как прокомментировал Джон Лин,
ls -al
всегда будет выводить (для.
и..
). Вы хотитеls -Al
избежать этих двух каталогов.Например, вы можете поместить вывод команды в переменную оболочки:
Старая, нестабильная запись
но я предпочитаю вложенные обозначения
$(
...)
Вы можете проверить, если эта переменная не пуста
И вы могли бы объединить как
if [ -n "$(ls -Al)" ]; then
источник
Я предполагаю, что вы хотите вывод
ls -al
команды, поэтому в bash вы получите что-то вроде:источник
ls
никогда не выполняется. Вы только проверяете, является ли раскрытие переменнойLS
непустым.-a
Выключатель никогда не будет возвращать никакого содержания (то есть, он будет возвращать содержимое , есть ли файлы или нет) , так как всегда есть неявная.
и..
каталоги присутствуют.Вот решение для более экстремальных случаев:
Это будет работать
тем не мение,
источник
Все приведенные ответы касаются команд, которые завершают и выводят непустую строку.
Большинство из них сломаны в следующих смыслах:
yes
).Таким образом, чтобы исправить все эти проблемы и эффективно ответить на следующий вопрос,
ты можешь использовать:
Вы можете также добавить некоторые тайм - аут для того, чтобы тест выдает ли команда не пустую строку в данный момент времени, используя
read
«s-t
варианта. Например, в течение 2,5 секунд:Замечание. Если вы считаете, что вам нужно определить, выводит ли команда непустую строку, у вас, скорее всего, проблема XY.
источник
seq 1 10000000
,seq 1 20
иprintf""
). Единственный матч, который этот подход чтения не выиграл, был с-z "$(command)"
подходом для пустого ввода. Даже тогда он проигрывает только на 10-15%. Кажется, они безубыточныseq 1 10
. Несмотря на это,-z "$(command)"
подход становится настолько медленным с ростом размера ввода, что я бы избегал использовать его для любого ввода переменного размера.Вот альтернативный подход, который записывает std-out и std-err некоторой команды во временный файл, а затем проверяет, является ли этот файл пустым. Преимущество этого подхода состоит в том, что он захватывает оба выхода и не использует подоболочки или каналы. Эти последние аспекты важны, потому что они могут помешать перехвату обработки выхода bash (например, здесь )
источник
Иногда вы хотите сохранить вывод, если он не пустой, чтобы передать его другой команде. Если это так, вы можете использовать что-то вроде
Таким образом,
rm
команда не будет зависать, если список пуст.источник