Itérer sur la sortie d'une commande dans bash sans sous-shell

9

Je veux parcourir la sortie d'une commande sans créer de sous-shell ou utiliser un fichier temporaire.

La version initiale de mon script ressemblait à ceci, mais cela ne fonctionne pas car elle crée un sous-shell, et la exitcommande termine le sous-shell au lieu du script principal qui est requis. Il fait partie d'un script beaucoup plus volumineux pour configurer le routage de stratégie et arrête l'exécution s'il détecte une condition qui entraînera l'échec du routage.

sysctl -a 2>/dev/null | grep '\.rp_filter' | while read -r -a RPSTAT ; do

  if [[ "0" != "${RPSTAT[2]}" ]] ; then
    echo >&2 "RP Filter must be disabled on all interfaces!"
    echo >&2 "The RP filter feature is incompatible with policy routing"
    exit 1
  fi
done

Une des alternatives suggérées est donc d'utiliser une commande comme celle-ci pour éviter le sous-shell.

while read BLAH ; do echo $BLAH; done </root/regularfile

Il me semble donc que je devrais également pouvoir utiliser une commande comme celle-ci pour éviter le sous-shell et toujours obtenir la sortie du programme que je veux.

while read BLAH ; do echo $BLAH; done <(sysctl -a 2>/dev/null | grep '\.rp_filter')

Malheureusement, l'utilisation de cette commande entraîne cette erreur.

-bash: syntax error near unexpected token `<(sysct ...

Je suis vraiment confus car cela fonctionne.

cat <(sysctl -a 2>/dev/null | grep '\.rp_filter')

Je pouvais enregistrer la sortie de cette commande dans un fichier temporaire et utiliser la redirection sur le fichier temporaire, mais je voulais éviter de le faire.

Alors pourquoi la redirection me donne-t-elle une erreur et ai-je d'autres options que la création d'un fichier temporaire?

Zoredache
la source

Réponses:

13

Vous avez raté un <. Devrait être:

while read BLAH ; do echo $BLAH; done < <(sysctl -a 2>/dev/null | grep '\.rp_filter')

Pensez à <(sysctl -a 2>/dev/null | grep '\.rp_filter')être un fichier.

dogbane
la source
Merci beaucoup. Juste pour mon édification, pouvez-vous me diriger vers une page de manuel, une aide ou une page Web qui documente cela? Je n'ai pas réussi à faire en sorte que Google me pointe vers quoi que ce soit d'utile lors de la recherche.
Zoredache
2
Google "substitution de processus". par exemple tldp.org/LDP/abs/html/abs-guide.html#PROCESS-SUB
dogbane
Il convient de noter que la substitution <() utilise des descripteurs de fichiers et sur certains systèmes d'exploitation créera et utilisera de manière transparente des fichiers temporaires.
ewindisch
@Zoredache: recherchez simplement <(dans le manuel bash (il se trouve sous «substitution de processus»).
Gilles 'SO- arrête d'être méchant'
@ewindisch, si un outil crée de manière transparente un fichier temporaire qui est bien, je ne voulais tout simplement pas en créer un manuellement, alors que j'étais à peu près sûr que je n'en avais pas besoin.
Zoredache
0

Pour quelques autres alternatives si quelqu'un revient ici ...

En fonction du shell, vous pourriez probablement utiliser set -o errexitpour que le shell parent se termine lorsqu'une commande (y compris un sous-shell) quitte non nul sans être piégée dans un ifbloc ou un trailing &&ou ||, comme dans

/bin/false || echo "ignoring error"

Vous pouvez également demander au sous-shell de signaler au parent à l'aide de kill et de la variable d'environnement $ PPID, si disponible.

Ou vous pouvez déplacer le bloc while dans une fonction et retourner 0/1 (renvoyer explicitement 0 après le bloc while) et simplement faire votre pipeline comme sysctl | grep | function || exit. Je suppose que vous pouvez également mettre les retours dans le bloc en ligne, mais les fonctions sont votre ami. ;)

dannysauer
la source