Como posso testar se um comando gera uma string vazia?
ifne
para isso. joeyh.name/code/moreutils
Como posso testar se um comando gera uma string vazia?
ifne
para isso. joeyh.name/code/moreutils
Respostas:
Anteriormente, a pergunta era como verificar se há arquivos em um diretório. O código a seguir consegue isso, mas consulte a resposta da rsp para obter uma solução melhor.
Os comandos não retornam valores - eles os produzem. Você pode capturar essa saída usando substituição de comando ; por exemplo $(ls -A)
. Você pode testar uma cadeia de caracteres não vazia no Bash assim:
if [[ $(ls -A) ]]; then
echo "there are files"
else
echo "no files found"
fi
Note que eu usei -A
em vez de -a
, uma vez que omite a corrente simbólica ( .
) e pai ( ..
entradas de diretório).
Nota: Conforme indicado nos comentários, a substituição de comandos não captura as novas linhas à direita . Portanto, se o comando gerar apenas novas linhas, a substituição não capturará nada e o teste retornará falso. Embora muito improvável, isso é possível no exemplo acima, pois uma única nova linha é um nome de arquivo válido! Mais informações nesta resposta .
Se você deseja verificar se o comando foi concluído com êxito, é possível inspecionar $?
, que contém o código de saída do último comando (zero para êxito, diferente de zero para falha). Por exemplo:
files=$(ls -A)
if [[ $? != 0 ]]; then
echo "Command failed."
elif [[ $files ]]; then
echo "Files found."
else
echo "No files found."
fi
Mais informações aqui .
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then ...; fi
Agradeço ao netj
por uma sugestão para melhorar meu original:if [[ $(ls -A | wc -c) -ne 0 ]]; then ...; fi
Esta é uma pergunta antiga, mas vejo pelo menos duas coisas que precisam de melhorias ou pelo menos alguns esclarecimentos.
O primeiro problema que vejo é que a maioria dos exemplos fornecidos aqui simplesmente não funciona . Eles usam os comandos ls -al
e ls -Al
- ambos produzem cadeias não vazias em diretórios vazios. Esses exemplos sempre relatam que existem arquivos, mesmo quando não existem .
Por esse motivo, você deve usar apenas ls -A
- Por que alguém iria querer usar a -l
opção que significa "usar um formato de listagem longo" quando tudo o que você quer é testar se há alguma saída ou não, afinal?
Portanto, a maioria das respostas aqui são simplesmente incorretas.
O segundo problema é que, enquanto algumas respostas funcionar bem (aqueles que não usam ls -al
ou ls -Al
, mas ls -A
em vez disso) todos eles fazem algo como isto:
O que eu sugeriria fazer seria:
using head -c1
Então, por exemplo, em vez de:
if [[ $(ls -A) ]]
Eu usaria:
if [[ $(ls -A | wc -c) -ne 0 ]]
# or:
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]
Ao invés de:
if [ -z "$(ls -lA)" ]
Eu usaria:
if [ $(ls -lA | wc -c) -eq 0 ]
# or:
if [ $(ls -lA | head -c1 | wc -c) -eq 0 ]
e assim por diante.
Para saídas pequenas, pode não ser um problema, mas para saídas maiores a diferença pode ser significativa:
$ time [ -z "$(seq 1 10000000)" ]
real 0m2.703s
user 0m2.485s
sys 0m0.347s
Compare com:
$ time [ $(seq 1 10000000 | wc -c) -eq 0 ]
real 0m0.128s
user 0m0.081s
sys 0m0.105s
E ainda melhor:
$ time [ $(seq 1 10000000 | head -c1 | wc -c) -eq 0 ]
real 0m0.004s
user 0m0.000s
sys 0m0.007s
Exemplo atualizado da resposta de Will Vousden:
if [[ $(ls -A | wc -c) -ne 0 ]]; then
echo "there are files"
else
echo "no files found"
fi
Atualizado novamente após sugestões de netj :
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then
echo "there are files"
else
echo "no files found"
fi
Atualização adicional por jakeonfire :
grep
sairá com falha se não houver correspondência. Podemos tirar vantagem disso para simplificar um pouco a sintaxe:
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
Se o comando que você está testando pode gerar algum espaço em branco que você deseja tratar como uma sequência vazia, em vez de:
| wc -c
você poderia usar:
| tr -d ' \n\r\t ' | wc -c
ou com head -c1
:
| tr -d ' \n\r\t ' | head -c1 | wc -c
ou algo assim.
Primeiro, use um comando que funcione .
Segundo, evite o armazenamento desnecessário na RAM e o processamento de dados potencialmente enormes.
A resposta não especificou que a saída é sempre pequena; portanto, uma possibilidade de saída grande também deve ser considerada.
[[ $(... | head -c | wc -c) -gt 0 ]]
ou [[ -n $(... | head -c1) ]]
são melhores porque wc -c
teriam que consumir toda a saída do comando.
if [ -z "$(ls -lA)" ]; then
echo "no files found"
else
echo "There are files"
fi
Isso executará o comando e verificará se a saída retornada (string) tem um comprimento zero. Você pode verificar as páginas de manual 'teste' para outros sinalizadores.
Use o "" em volta do argumento que está sendo verificado, caso contrário, resultados vazios resultarão em um erro de sintaxe, pois não há um segundo argumento (para verificar) fornecido!
Nota: isso ls -la
sempre retorna .
e, ..
portanto, usá-lo não funciona, consulte as páginas de manual . Além disso, embora isso possa parecer conveniente e fácil, suponho que ele se quebre facilmente. Escrever um pequeno script / aplicativo que retorne 0 ou 1, dependendo do resultado, é muito mais confiável!
$(
em vez de crase, porque $(
ninho melhor
Para aqueles que desejam uma solução elegante e independente da versão do bash (de fato, deve funcionar em outros shells modernos) e aqueles que gostam de usar one-liners para tarefas rápidas. Aqui vamos nós!
ls | grep . && echo 'files found' || echo 'files not found'
(observe como um dos comentários mencionados ls -al
e, de fato, apenas -l
e -a
todos retornarão algo, por isso, na minha resposta,ls
grep -q ^
, os caracteres de nova linha também serão correspondidos e o grep não imprimirá nada na saída padrão. Além disso, ele será encerrado assim que receber qualquer entrada, em vez de aguardar o término do fluxo de entrada.
ls -A
se você quiser incluir arquivos de ponto (ou diretórios)
-z string
True if the length of string is zero.
-n string
string
True if the length of string is non-zero.
Você pode usar a versão abreviada:
if [[ $(ls -A) ]]; then
echo "there are files"
else
echo "no files found"
fi
string
é apenas um sinônimo -n string
.
Como Jon Lin comentou, ls -al
sempre produzirá (para .
e ..
). Você deseja ls -Al
evitar esses dois diretórios.
Você pode, por exemplo, colocar a saída do comando em uma variável do shell:
v=$(ls -Al)
Uma notação mais antiga e não aninhada é
v=`ls -Al`
mas eu prefiro a notação aninhada $(
...)
Você pode testar se essa variável não está vazia
if [ -n "$v" ]; then
echo there are files
else
echo no files
fi
E você pode combinar tanto quanto if [ -n "$(ls -Al)" ]; then
Suponho que você queira a saída do ls -al
comando, portanto, no bash, você terá algo como:
LS=`ls -la`
if [ -n "$LS" ]; then
echo "there are files"
else
echo "no files found"
fi
ls
nunca está sendo executado. Você só verifica se a expansão da variável LS
não está vazia.
-a
opção nunca retornará conteúdo (isto é, retornará conteúdo, independentemente de haver arquivos ou não), pois sempre há os diretórios implícitos .
e ..
presentes.
Aqui está uma solução para casos mais extremos:
if [ `command | head -c1 | wc -c` -gt 0 ]; then ...; fi
Isso vai funcionar
Contudo,
Todas as respostas dadas até agora tratam de comandos que terminam e emitem uma sequência não vazia.
A maioria é quebrada nos seguintes sentidos:
yes
).Portanto, para corrigir todos esses problemas e responder com eficiência à seguinte pergunta,
Como posso testar se um comando gera uma string vazia?
você pode usar:
if read -n1 -d '' < <(command_here); then
echo "Command outputs something"
else
echo "Command doesn't output anything"
fi
Você também pode adicionar algum tempo limite para testar se um comando gera uma seqüência de caracteres não vazia dentro de um determinado tempo, usando read
a -t
opção 's . Por exemplo, por um tempo limite de 2,5 segundos:
if read -t2.5 -n1 -d '' < <(command_here); then
echo "Command outputs something"
else
echo "Command doesn't output anything"
fi
Observação. Se você acha que precisa determinar se um comando gera uma sequência não vazia, é muito provável que tenha um problema XY.
seq 1 10000000
, seq 1 20
, e printf""
). A única combinação que essa abordagem de leitura não venceu foi com a -z "$(command)"
abordagem de uma entrada vazia. Mesmo assim, perde apenas entre 10 e 15%. Eles parecem se equilibrar seq 1 10
. Independentemente disso, a -z "$(command)"
abordagem se torna tão lenta quanto o tamanho da entrada aumenta, que eu evitaria usá-la para qualquer entrada de tamanho variável.
Aqui está uma abordagem alternativa que grava o std-out e std-err de algum comando em um arquivo temporário e, em seguida, verifica se esse arquivo está vazio. Um benefício dessa abordagem é que ela captura as duas saídas e não usa subcascas ou tubos. Esses últimos aspectos são importantes porque eles podem interferir no manuseio de saída da saída do bash (por exemplo, aqui )
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"
Às vezes, você deseja salvar a saída, se não estiver vazia, para passá-la para outro comando. Nesse caso, você poderia usar algo como
list=`grep -l "MY_DESIRED_STRING" *.log `
if [ $? -eq 0 ]
then
/bin/rm $list
fi
Dessa forma, o rm
comando não será interrompido se a lista estiver vazia.