Vérifier si la commande renvoie une chaîne vide

Comment puis-je tester si une commande affiche une chaîne vide?

146
demandé sur Tshepang 2012-08-27 10:53:37

11 réponses

auparavant, la question demandait Comment vérifier s'il y avait des fichiers dans un répertoire. Le code suivant permet d'atteindre cet objectif, mais voir réponse de rsp pour une meilleure solution.


Vide "sortie

Les commandes

ne donnent pas les valeurs return – elles les produisent. Vous pouvez capturer cette sortie en utilisant la substitution de commande ; p.ex. $(ls -A) . Vous pouvez tester une chaîne non vide dans Bash comme ceci:

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

notez que j'ai utilisé -A plutôt que -a , car il omet les entrées de répertoire courant symbolique ( . ) et parent ( .. ).

Note: tel que souligné dans les commentaires, la substitution de commande ne permet pas de capturer les nouvelles lignes traînantes . Par conséquent, si la commande affiche seulement newlines, la substitution ne capturera rien et le test retournera false. Bien que très improbable, ceci est possible dans l'exemple ci-dessus, puisqu'une seule ligne est un nom de fichier valide! Plus d'informations dans cette réponse .


code de Sortie

si vous voulez vérifier que la commande a été exécutée avec succès, vous pouvez inspecter $? , qui contient le code de sortie de la dernière commande (zéro pour le succès, non-zéro de l'échec). Par exemple:

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

Plus d'infos ici .

206
répondu Will Vousden 2017-05-23 11:47:21

TL; DR

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

merci à netj pour une suggestion pour améliorer mon original:

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


C'est une vieille question, mais je vois au moins deux choses qui ont besoin d'une amélioration ou au moins quelques éclaircissements.

premier problème

le premier problème que je vois est que la plupart des les exemples fournis ici ne fonctionnent tout simplement pas . Ils utilisent les commandes ls -al et ls -Al , qui produisent toutes deux des chaînes non vides dans des répertoires vides. Ces exemples toujours rapportent qu'il y a des fichiers même s'il n'y en a aucun .

pour cette raison, vous devez utiliser juste ls -A - pourquoi quelqu'un voudrait utiliser le commutateur -l qui signifie " utiliser une longue liste format" quand tout ce que vous voulez est test s'il ya une sortie ou pas, de toute façon?

donc la plupart des réponses ici sont tout simplement incorrectes.

Second problème

le deuxième problème est que tandis que certains réponses fonctionne très bien (ceux qui ne utiliser ls -al ou ls -Al mais ls -A à la place) ils font tous quelque chose comme ceci:

  1. exécuter une commande
  2. buffer toute sa sortie en RAM
  3. convertissez la sortie en une chaîne monoligne énorme
  4. comparez cette chaîne à une chaîne vide

ce que je suggérerais plutôt serait:

  1. exécuter une commande
  2. compter les caractères dans sa sortie sans les stocker
    • ou encore mieux-count le nombre de caractères maximum 1 using head -c1

      (merci à netj pour avoir posté cette idée dans les commentaires ci-dessous)
  3. comparez ce nombre avec zéro

ainsi par exemple, au lieu de:

if [[ $(ls -A) ]]

je voudrais utiliser:

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

au lieu de:

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

j'utiliserais:

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

et ainsi de suite.

pour les petites sorties, ce n'est peut-être pas un problème, mais pour les plus grandes, la différence peut être significative:

$ time [ -z "$(seq 1 10000000)" ]

real    0m2.703s
user    0m2.485s
sys 0m0.347s

Comparez avec:

$ time [ $(seq 1 10000000 | wc -c) -eq 0 ]

real    0m0.128s
user    0m0.081s
sys 0m0.105s

et encore mieux:

$ time [ $(seq 1 10000000 | head -c1 | wc -c) -eq 0 ]

real    0m0.004s
user    0m0.000s
sys 0m0.007s

exemple complet

exemple mis à jour de la réponse de Will Vousden:

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

à nouveau mis à jour après les suggestions de netj :

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

si la commande que vous êtes en train de tester pourrait produire un espace que vous voulez traiter comme une chaîne vide, alors au lieu de:

| wc -c

vous pouvez utiliser:

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

ou avec head -c1 :

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

ou quelque chose comme ça.

résumé

  1. tout d'abord, utilisez une commande qui fonctionne .

  2. Deuxièmement, éviter le stockage inutile en RAM et le traitement de données potentiellement énormes.

la réponse ne précisait pas que la sortie était toujours petite, donc une possibilité de grande sortie doit être considérée aussi.

64
répondu rsp 2017-05-10 08:59:29
if [ -z "$(ls -lA)" ]; then
  echo "no files found"
else
  echo "There are files"
fi

cela lancera la commande et vérifiera si la sortie retournée (chaîne) a une longueur zéro. Vous pouvez vérifier les pages de manuel "test " pour d'autres options.

utilisez le "" autour de l'argument qui est vérifié, sinon les résultats vides résulteront en une erreur de syntaxe car il n'y a pas de second argument (à vérifier) donné!

Note: que ls -la retourne toujours . et .. ainsi en utilisant cela ne fonctionnera pas, voir ls manual pages . En outre, bien que cela puisse sembler commode et facile, je suppose qu'il se cassera facilement. Écrire un petit script / application qui renvoie 0 ou 1 en fonction du résultat est beaucoup plus fiable!

23
répondu Veger 2018-09-04 10:30:02

pour ceux qui veulent une solution élégante, indépendante de la version de bash (en fait devrait fonctionner dans d'autres coquillages modernes) et ceux qui aiment à utiliser des couches simples pour des tâches rapides. Ici nous allons!

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

(note comme l'un des commentaires mentionnés, ls -al et en fait, juste -l et -a vont tous retourner quelque chose, donc dans ma réponse, j'utilise simple ls

16
répondu Alex 2014-08-26 01:12:50

comme L'a commenté Jon Lin, ls -al sortira toujours (pour . et .. ). Vous voulez ls -Al pour éviter ces deux répertoires.

vous pouvez par exemple mettre la sortie de la commande dans une variable shell:

v=$(ls -Al)

d'Un certain âge, non empilable, la notation est

v=`ls -Al`

mais je préfère la notation $( ... )

vous peut tester si cette variable n'est pas vide

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

et vous pouvez combiner les deux comme if [ -n "$(ls -Al)" ]; then

9
répondu Basile Starynkevitch 2012-08-27 07:00:29

Bash Manuel De Référence

6.4 Bash Expressions Conditionnelles

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

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

vous pouvez utiliser la version abrégée:

if [[ $(ls -A) ]]; then
  echo "there are files"
else
  echo "no files found"
fi
8
répondu user 2014-05-08 04:25:39

je suppose que vous voulez la sortie de la commande ls -al , donc en bash, vous avez quelque chose comme:

LS=`ls -la`

if [ -n "$LS" ]; then
  echo "there are files"
else
  echo "no files found"
fi
3
répondu Jon Lin 2012-08-27 07:06:47

Voici une solution pour les cas extrêmes:

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

Cela fonctionne

  • pour tous les shells Bourne;
  • si la commande affiche tous les zéros;
  • efficacement quelle que soit la taille de sortie;

toutefois,

  • la commande ou ses sous-processus seront tués une fois que quelque chose est sorti.
2
répondu Curt 2016-01-14 02:36:19

Voici une approche alternative qui écrit Le std-out et le std-err d'une commande un fichier temporaire, et vérifie ensuite si ce fichier est vide. L'un des avantages de cette approche est qu'elle permet de saisir les deux extrants et qu'elle n'utilise pas de sous-coquilles ou de tuyaux. Ces derniers aspects sont importants parce qu'ils peuvent interférer avec la manipulation des sorties bash (par exemple ici )

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"
0
répondu Darren Smith 2018-04-27 11:20:29

Parfois, vous voulez enregistrer la sortie, si c'est non-vide, pour passer à une autre commande. Si c'est le cas, vous pouvez utiliser quelque chose comme

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

de cette façon, la commande rm ne sera pas suspendue si la liste est vide.

0
répondu Scott C Wilson 2018-05-28 10:35:18

toutes les réponses données jusqu'à présent traitent de commandes que termineront et produisent une chaîne non vide.

la plupart sont cassés dans les sens suivants:

  • Ils ne traitent pas correctement avec les commandes de la sortie seulement des retours à la ligne;
  • à partir de Bash≥4.4 most va spam erreur standard si la commande sortie octets null (comme ils utilisent la substitution de commande);
  • la plupart slurp le flux de sortie complet, alors attend jusqu'à ce que la commande se termine avant de répondre. Certaines commandes ne se terminent jamais (essayez, par exemple, yes ).

donc pour corriger toutes ces questions, et de répondre à la question suivante efficacement,

Comment puis-je tester si une commande affiche une chaîne vide?

vous pouvez utiliser:

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

vous pouvez également ajouter un timeout pour tester si une commande affiche une chaîne non vide dans un temps donné, en utilisant l'option read 's -t . Par exemple, pour un temps d'arrêt de 2,5 secondes:

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

Remarque. si vous pensez que vous avez besoin de déterminer si une commande affiche une chaîne non vide, vous avez très probablement un problème XY.

-1
répondu gniourf_gniourf 2016-10-05 09:12:37