J'ai besoin de lire la sortie d'une commande dans mon script dans un tableau. La commande est, par exemple:
ps aux | grep | grep | x
et il donne la sortie ligne par ligne comme ceci:
10
20
30
J'ai besoin de lire les valeurs de la sortie de la commande dans un tableau, puis je ferai du travail si la taille du tableau est inférieure à trois.
Réponses:
Les autres réponses éclateront si la sortie de la commande contient des espaces ( ce qui est assez fréquent) ou des personnages comme glob
*
,?
,[...]
.Pour obtenir la sortie d'une commande dans un tableau, avec une ligne par élément, il existe essentiellement 3 façons:
Avec Bash≥4
mapfile
, c'est le plus efficace:Sinon, une boucle lisant la sortie (plus lente, mais sûre):
Comme suggéré par Charles Duffy dans les commentaires (merci!), Ce qui suit pourrait fonctionner mieux que la méthode en boucle du numéro 2:
Veuillez vous assurer que vous utilisez exactement ce formulaire, c'est-à-dire que vous disposez des éléments suivants:
IFS=$'\n'
sur la même ligne que l'read
instruction: cela ne définira la variable d'environnement queIFS
pour l'read
instruction uniquement. Cela n'affectera donc pas du tout le reste de votre script. Le but de cette variable est de direread
de couper le flux au caractère EOL\n
.-r
: c'est important. Il ditread
de ne pas interpréter les contre-obliques comme des séquences d'échappement.-d ''
: veuillez noter l'espace entre l'-d
option et son argument''
. Si vous ne laissez pas d'espace ici, le''
ne sera jamais vu, car il disparaîtra lors de l' étape de suppression du devis lorsque Bash analysera l'instruction. Cela indiqueread
d'arrêter la lecture à l'octet nul. Certaines personnes l'écrivent comme-d $'\0'
, mais ce n'est pas vraiment nécessaire.-d ''
est mieux.-a my_array
ditread
de remplir le tableaumy_array
lors de la lecture du flux.printf '\0'
instruction aprèsmy_command
, de sorte queread
retourne0
; ce n'est en fait pas un gros problème si vous ne le faites pas (vous obtiendrez simplement un code de retour1
, ce qui est bien si vous ne l'utilisez passet -e
- ce que vous ne devriez pas de toute façon), mais gardez cela à l'esprit. C'est plus propre et plus sémantiquement correct. Notez que c'est différent deprintf ''
, qui ne produit rien.printf '\0'
affiche un octet nul, nécessaireread
pour arrêter joyeusement la lecture (vous vous souvenez de l'-d ''
option?).Si vous le pouvez, c'est-à-dire si vous êtes sûr que votre code fonctionnera sur Bash≥4, utilisez la première méthode. Et vous pouvez voir que c'est plus court aussi.
Si vous souhaitez l'utiliser
read
, la boucle (méthode 2) peut avoir un avantage sur la méthode 3 si vous souhaitez effectuer un traitement au fur et à mesure que les lignes sont lues: vous y avez un accès direct (via la$line
variable dans l'exemple que j'ai donné), et vous avez également accès aux lignes déjà lues (via le tableau${my_array[@]}
dans l'exemple que j'ai donné).Notez que cela
mapfile
fournit un moyen d'avoir un rappel évalué sur chaque ligne lue, et en fait vous pouvez même lui dire de n'appeler ce rappel que toutes les N lignes lues; jetez un oeil àhelp mapfile
et les options-C
et-c
là - dedans. (Mon opinion à ce sujet est que c'est un peu maladroit, mais peut être utilisé parfois si vous n'avez que des choses simples à faire - je ne comprends pas vraiment pourquoi cela a même été implémenté en premier lieu!).Maintenant, je vais vous dire pourquoi la méthode suivante:
est cassé lorsqu'il y a des espaces:
Ensuite, certaines personnes recommanderont d'utiliser
IFS=$'\n'
pour le réparer:Mais maintenant, utilisons une autre commande, avec des globs :
C'est parce que j'ai un fichier appelé
t
dans le répertoire courant ... et ce nom de fichier correspond au glob[three four]
... à ce stade, certaines personnes recommanderaient d'utiliserset -f
pour désactiver le globbing: mais regardez-le: vous devez changerIFS
et utiliserset -f
pour pouvoir réparer un technique cassée (et vous ne la réparez même pas vraiment)! en faisant cela, nous luttons vraiment contre le shell, pas avec le shell .ici nous travaillons avec le shell!
la source
mapfile
auparavant, c'est exactement ce qui me manque depuis des années. Je suppose que les versions récentes debash
ont tellement de nouvelles fonctionnalités intéressantes, je devrais juste passer quelques jours à lire la documentation et à écrire une belle feuille de triche.< <(command)
dans les scripts shell, la ligne shebang doit être#!/bin/bash
- si elle est exécutée en tant que#!/bin/sh
, bash se terminera avec une erreur de syntaxe.bash my_script.sh
et non la commande shsh my_script.sh
sh
etdash
ne connaissent pas du tout les tableaux, sauf, bien sûr, pour le$@
tableau des paramètres de position ).IFS=$'\n' read -r -d '' -a my_array < <(my_command && printf '\0')
cela fonctionne correctement dans bash 3.x et passe également par un état de sortie d'échec demy_command
àread
.Vous pouvez utiliser
pour stocker la sortie de la commande
<command>
dans le tableaumy_array
.Vous pouvez accéder à la longueur de ce tableau en utilisant
Maintenant, la longueur est stockée dans
my_array_length
.la source
VAR="$(<command>)"
et puismy_array=("$VAR")
oumy_array+=("$VAR")
Imaginez que vous allez mettre les fichiers et les noms de répertoire (sous le dossier actuel) dans un tableau et compter ses éléments. Le script serait comme;
Ou, vous pouvez parcourir ce tableau en ajoutant le script suivant:
Veuillez noter que c'est le concept de base et que l'entrée est considérée comme nettoyée avant, c'est-à-dire supprimer des caractères supplémentaires, gérer des chaînes vides, etc. (ce qui est hors du sujet de ce fil).
la source