Vérifier si la commande renvoie une chaîne vide
Comment puis-je tester si une commande affiche une chaîne vide?
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 .
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:
- exécuter une commande
- buffer toute sa sortie en RAM
- convertissez la sortie en une chaîne monoligne énorme
- comparez cette chaîne à une chaîne vide
ce que je suggérerais plutôt serait:
- exécuter une commande
- 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)
- ou encore mieux-count le nombre de caractères maximum 1
- 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é
-
tout d'abord, utilisez une commande qui fonctionne .
-
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.
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!
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
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
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
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
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.
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"
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.
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.