Comment puis-je tester si une commande génère une chaîne vide?
ifne
pour cela. joeyh.name/code/moreutils
Comment puis-je tester si une commande génère une chaîne vide?
ifne
pour cela. joeyh.name/code/moreutils
Réponses:
Auparavant, la question demandait comment vérifier s'il y avait des fichiers dans un répertoire. Le code suivant y parvient, mais consultez la réponse de rsp pour une meilleure solution.
Les commandes ne renvoient pas de valeurs - elles les produisent. Vous pouvez capturer cette sortie en utilisant la substitution de commande ; par exemple $(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 symboliques du répertoire courant ( .
) et parent ( ..
).
Remarque: Comme indiqué dans les commentaires, la substitution de commandes ne capture pas les sauts de ligne de fin . Par conséquent, si la commande ne produit que des sauts de ligne, la substitution ne capturera rien et le test renverra false. Bien que très peu probable, cela est possible dans l'exemple ci-dessus, car une seule nouvelle ligne est un nom de fichier valide! Plus d'informations dans cette réponse .
Si vous souhaitez vérifier que la commande s'est terminée avec succès, vous pouvez l'inspecter $?
, qui contient le code de sortie de la dernière commande (zéro pour la réussite, non nul pour 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 .
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 nécessitent des améliorations ou au moins des clarifications.
Le premier problème que je vois est que la plupart des exemples fournis ici ne fonctionnent tout simplement pas . Ils utilisent les commandes ls -al
et ls -Al
- qui produisent toutes les deux des chaînes non vides dans des répertoires vides. Ces exemples indiquent toujours qu'il y a des fichiers même quand il n'y en a pas .
Pour cette raison, vous devez utiliser simplement ls -A
- Pourquoi quelqu'un voudrait-il utiliser le -l
commutateur qui signifie "utiliser un format de liste longue" alors que tout ce que vous voulez, c'est tester s'il y a une sortie ou non, de toute façon?
La plupart des réponses ici sont donc tout simplement incorrectes.
Le deuxième problème est que , même si certaines réponses fonctionnent très bien (ceux qui ne sont pas utiliser ls -al
ou ls -Al
mais ls -A
plutôt) ils font tous quelque chose comme ceci:
Ce que je suggère de faire à la place serait:
using head -c1
Ainsi, par exemple, au lieu de:
if [[ $(ls -A) ]]
J'utiliserais:
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 ]
etc.
Pour les petites sorties, cela peut ne pas être un problème, mais pour les sorties plus grandes, la différence peut être significative:
$ time [ -z "$(seq 1 10000000)" ]
real 0m2.703s
user 0m2.485s
sys 0m0.347s
Comparez-le 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 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
Mis à jour à nouveau 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
Mise à jour supplémentaire par jakeonfire :
grep
se terminera avec un échec s'il n'y a pas de correspondance. Nous pouvons en profiter pour simplifier légèrement la syntaxe:
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
Si la commande que vous testez peut générer des espaces que vous souhaitez traiter comme une chaîne vide, alors au lieu de:
| wc -c
vous pourriez 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.
Tout d'abord, utilisez une commande qui fonctionne .
Deuxièmement, évitez le stockage inutile dans la RAM et le traitement de données potentiellement énormes.
La réponse n'a pas précisé que la sortie est toujours petite, donc une possibilité de sortie importante doit également être considérée.
[[ $(... | head -c | wc -c) -gt 0 ]]
ou [[ -n $(... | head -c1) ]]
sont mieux car wc -c
devraient consommer la sortie entière de la commande.
if [ -z "$(ls -lA)" ]; then
echo "no files found"
else
echo "There are files"
fi
Cela exécutera la commande et vérifiera si la sortie renvoyée (chaîne) a une longueur nulle. Vous voudrez peut-être vérifier les pages de manuel «test» pour d'autres indicateurs.
Utilisez le "" autour de l'argument en cours de vérification, sinon les résultats vides entraîneront une erreur de syntaxe car il n'y a pas de deuxième argument (à vérifier) donné!
Remarque: cela ls -la
revient toujours .
et ..
donc l'utilisation qui ne fonctionnera pas, voir les pages de manuel ls . De plus, bien que cela puisse sembler pratique et facile, je suppose que cela se cassera facilement. Écrire un petit script / application qui renvoie 0 ou 1 selon le résultat est beaucoup plus fiable!
$(
place de la $(
Pour ceux qui veulent une solution élégante et indépendante de la version bash (en fait, devraient fonctionner dans d'autres shells modernes) et ceux qui aiment utiliser des lignes simples pour des tâches rapides. Et c'est parti!
ls | grep . && echo 'files found' || echo 'files not found'
(notez que l'un des commentaires mentionnés, ls -al
et en fait, juste -l
et -a
retournera tous quelque chose, donc dans ma réponse j'utilise simplels
grep -q ^
place, les caractères de nouvelle ligne seront également mis en correspondance et grep n'imprimera rien sur la sortie standard. De plus, il quittera dès qu'il recevra une entrée, plutôt que d'attendre la fin de son flux d'entrée.
ls -A
si vous souhaitez inclure des fichiers dot (ou répertoires)
-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
string
n'est qu'un synonyme de -n string
.
Comme l'a commenté Jon Lin, ls -al
sera toujours affiché (pour .
et ..
). Vous voulez ls -Al
éviter ces deux répertoires.
Vous pouvez par exemple mettre la sortie de la commande dans une variable shell:
v=$(ls -Al)
Une notation plus ancienne et non emboîtable est
v=`ls -Al`
mais je préfère la notation emboîtable $(
...)
Vous pouvez 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 if [ -n "$(ls -Al)" ]; then
Je suppose que vous voulez la sortie de la ls -al
commande, donc en bash, vous auriez quelque chose comme:
LS=`ls -la`
if [ -n "$LS" ]; then
echo "there are files"
else
echo "no files found"
fi
ls
n'est jamais en cours d'exécution. Vous vérifiez uniquement si l' expansion de la variable LS
n'est pas vide.
-a
commutateur ne renverra jamais aucun contenu (c'est-à-dire qu'il renverra du contenu, qu'il y ait des fichiers ou non) car il y a toujours les répertoires implicites .
et ..
présents.
Voici une solution pour les cas les plus extrêmes:
if [ `command | head -c1 | wc -c` -gt 0 ]; then ...; fi
Cela fonctionnera
cependant,
Toutes les réponses données jusqu'à présent concernent les commandes qui terminent et produisent une chaîne non vide.
La plupart sont brisés dans les sens suivants:
yes
).Donc, pour résoudre tous ces problèmes et répondre efficacement à la question suivante,
Comment puis-je tester si une commande génère 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 certain délai afin de tester si une commande génère une chaîne non vide dans un délai donné, en utilisant read
l' -t
option de. Par exemple, pour un délai 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 devez déterminer si une commande génère une chaîne non vide, vous avez très probablement un problème XY.
seq 1 10000000
, seq 1 20
et printf""
). Le seul affrontement que cette approche de lecture n'a pas gagné était avec l' -z "$(command)"
approche pour une entrée vide. Même alors, il ne perd qu'environ 10 à 15%. Ils semblent se rompre seq 1 10
. Quoi qu'il en soit, l' -z "$(command)"
approche devient si lente que la taille d'entrée augmente que j'éviterais de l'utiliser pour toute entrée de taille variable.
Voici une approche alternative qui écrit les std-out et std-err de certaines commandes dans un fichier temporaire, puis vérifie si ce fichier est vide. Un avantage de cette approche est qu'elle capture les deux sorties et n'utilise pas de sous-coques ou de tuyaux. Ces derniers aspects sont importants car ils peuvent interférer avec le trapping de la gestion 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 souhaitez enregistrer la sortie, si elle n'est pas vide, pour la passer à une autre commande. Si oui, 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 rm
commande ne se bloquera pas si la liste est vide.