Как я могу проверить, выводит ли команда пустую строку?
ifne
для этого. joeyh.name/code/moreutils
Как я могу проверить, выводит ли команда пустую строку?
ifne
для этого. joeyh.name/code/moreutils
Ответы:
Ранее задавался вопрос, как проверить, есть ли файлы в каталоге. Следующий код достигает этого, но см . Ответ rsp для лучшего решения.
Команды не возвращают значения - они выводят их. Вы можете захватить этот вывод, используя подстановку команд ; например $(ls -A)
. Вы можете проверить непустую строку в Bash следующим образом:
if [[ $(ls -A) ]]; then
echo "there are files"
else
echo "no files found"
fi
Обратите внимание, что я использовал -A
вместо -a
, так как он пропускает символические записи каталога current ( .
) и parent ( ..
).
Примечание. Как указано в комментариях, подстановка команд не захватывает завершающие символы новой строки . Следовательно, если команда выводит только новые строки, подстановка ничего не захватывает, а тест возвращает false. Хотя это очень маловероятно, это возможно в приведенном выше примере, поскольку одна новая строка является допустимым именем файла! Больше информации в этом ответе .
Если вы хотите проверить, успешно ли выполнена команда, вы можете проверить $?
, в которой содержится код завершения последней команды (ноль для успеха, ненулевое значение для сбоя). Например:
files=$(ls -A)
if [[ $? != 0 ]]; then
echo "Command failed."
elif [[ $files ]]; then
echo "Files found."
else
echo "No files found."
fi
Больше информации здесь .
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
Так, например, вместо:
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
Дополнительное обновление от jakeonfire :
grep
выйдет с ошибкой, если совпадений нет. Мы можем воспользоваться этим, чтобы немного упростить синтаксис:
if ls -A | head -c1 | grep -E '.'; then
echo "there are files"
fi
if ! ls -A | head -c1 | grep -E '.'; then
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
или что-то вроде того.
Сначала используйте команду, которая работает .
Во-вторых, избегайте ненужного хранения в оперативной памяти и обработки потенциально огромных данных.
В ответе не указывалось, что выходные данные всегда малы, поэтому необходимо учитывать возможность больших выходных данных.
[[ $(... | head -c | wc -c) -gt 0 ]]
или [[ -n $(... | head -c1) ]]
лучше, потому wc -c
что придется использовать весь вывод команды.
if [ -z "$(ls -lA)" ]; then
echo "no files found"
else
echo "There are files"
fi
Это запустит команду и проверит, имеет ли возвращаемый вывод (строка) нулевую длину. Возможно, вы захотите проверить справочные страницы «test» на наличие других флагов.
Используйте «» вокруг проверяемого аргумента, иначе пустые результаты приведут к синтаксической ошибке, поскольку второй аргумент (для проверки) не задан!
Обратите внимание, что ls -la
всегда возвращается .
и ..
поэтому использование этого не будет работать, см. Справочные страницы . Кроме того, хотя это может показаться удобным и легким, я полагаю, что оно легко сломается. Написание небольшого скрипта / приложения, которое возвращает 0 или 1 в зависимости от результата, гораздо надежнее!
$(
вместо обратной цитаты, потому что $(
гнездо лучше
Для тех, кто хочет элегантное решение, не зависящее от версии bash (на самом деле должно работать в других современных оболочках), и тех, кто любит использовать однострочники для быстрых задач. Вот так!
ls | grep . && echo 'files found' || echo 'files not found'
(обратите внимание, как один из упомянутых комментариев, ls -al
и на самом деле, просто -l
и -a
все что-то вернут, поэтому в своем ответе я использую простойls
grep -q ^
вместо этого, символы новой строки также будут сопоставлены, и grep не будет ничего выводить на стандартный вывод. Кроме того, он выйдет, как только получит какие-либо входные данные, вместо того, чтобы ждать окончания входного потока.
ls -A
если вы хотите включить точечные файлы (или каталоги)
-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
string
синоним -n string
.
Как прокомментировал Джон Лин, 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
Я предполагаю, что вы хотите вывод ls -al
команды, поэтому в bash вы получите что-то вроде:
LS=`ls -la`
if [ -n "$LS" ]; then
echo "there are files"
else
echo "no files found"
fi
ls
никогда не выполняется. Вы только проверяете, является ли раскрытие переменной LS
непустым.
-a
Выключатель никогда не будет возвращать никакого содержания (то есть, он будет возвращать содержимое , есть ли файлы или нет) , так как всегда есть неявная .
и ..
каталоги присутствуют.
Вот решение для более экстремальных случаев:
if [ `command | head -c1 | wc -c` -gt 0 ]; then ...; fi
Это будет работать
тем не мение,
Все приведенные ответы касаются команд, которые завершают и выводят непустую строку.
Большинство из них сломаны в следующих смыслах:
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.
seq 1 10000000
, seq 1 20
и printf""
). Единственный матч, который этот подход чтения не выиграл, был с -z "$(command)"
подходом для пустого ввода. Даже тогда он проигрывает только на 10-15%. Кажется, они безубыточны seq 1 10
. Несмотря на это, -z "$(command)"
подход становится настолько медленным с ростом размера ввода, что я бы избегал использовать его для любого ввода переменного размера.
Вот альтернативный подход, который записывает 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
команда не будет зависать, если список пуст.