Dis que j'ai le pipeline suivant:
cmd1 < input.txt |\
cmd2 |\
cmd4 |\
cmd5 |\
cmd6 |\
(...) |\
cmdN > result.txt
Dans certaines conditions, je voudrais ajouter un cmd3
entre cmd2
et cmd4
. Existe-t-il un moyen de créer une sorte de pipeline conditionnel sans économiser le résultat de cmd2
dans un fichier temporaire? Je penserais à quelque chose comme:
cmd1 < input.txt |\
cmd2 |\
(${DEFINED}? cmd3 : cat ) |\
cmd4 |\
cmd5 |\
cmd6 |\
(...) |\
cmdN > result.txt
Juste l'habituel &&
et ||
les opérateurs:
cmd1 < input.txt |
cmd2 |
( [ -n "$DEFINED" ] && cmd3 || cat ) |
cmd4 |
cmd5 |
cmd6 |
(...) |
cmdN > result.txt
(Notez qu'aucune barre oblique inverse n'est nécessaire lorsque la ligne se termine par le tuyau.)
Mise à jour Selon - Observation de Jonas ' .
[.____] Si cmd3 peut terminer avec un code de sortie non nul et que vous ne voulez pas cat
pour traiter l'entrée restante, inverser la logique:
cmd1 < input.txt |
cmd2 |
( [ -z "$DEFINED" ] && cat || cmd3 ) |
cmd4 |
cmd5 |
cmd6 |
(...) |
cmdN > result.txt
if
/else
/fi
fonctionne. En supposant que n'importe quel shell de Bourne:
cmd1 < input.txt |
cmd2 |
if [ -n "$DEFINED" ]; then cmd3; else cat; fi |
cmd4 |
cmd5 |
cmd6 |
(...) |
cmdN > result.txt
Toutes les réponses données jusqu'à présent remplacent cmd3
Avec cat
. Vous pouvez également éviter de courir n'importe quelle commande avec:
if [ -n "$DEFINE" ]; then
alias maybe_cmd3='cmd3 |'
else
alias maybe_cmd3=''
fi
cmd1 |
cmd2 |
maybe_cmd3
cmd4 |
... |
cmdN > result.txt
C'est POSIX, mais notez que si dans un script bash
_ _ bash
n'est pas dans sh
- mode (comme avec un script commençant par #! /path/to/bash
), Vous Il faut activer l'expansion d'alias avec shopt -s expand_aliases
(ou set -o posix
).
Une autre approche qui ne fonctionne toujours pas de commande inutile consiste à utiliser EVAL:
if [ -n "$DEFINE" ]; then
maybe_cmd3='cmd3 |'
else
maybe_cmd3=''
fi
eval "
cmd1 |
cmd2 |
$maybe_cmd3
cmd4 |
... |
cmdN > result.txt"
Ou:
eval "
cmd1 |
cmd2 |
${DEFINE:+cmd3 |}
cmd4 |
... |
cmdN > result.txt"
Sur Linux (au moins), au lieu de cat
, vous pouvez utiliser pv -q
Utilisé splice()
au lieu de read()
+ write()
pour passer Les données entre les deux tuyaux qui évitent de disposer des données déplacées deux fois entre le noyau et l'espace utilisateur.
Comme un addendum à réponse acceptée de Manatwork : Soyez conscient de la FALSE-FALS-OU GOTCHA et de son interaction avec des flux. Par exemple,
true && false || echo foo
sorties foo
. Sans surprise,
true && (echo foo | grep bar) || echo baz
et
echo foo | (true && grep bar || echo baz)
la sortie baz
. (Noter que echo foo | grep bar
est faux et n'a pas de sortie). Cependant,
echo foo | (true && grep bar || sed -e abaz)
sorties rien. Cela peut ou peut ne pas être ce que vous voulez.
J'ai eu une situation similaire que j'ai résolue avec Bash Fonctions:
if ...; then
my_cmd3() { cmd3; }
else
my_cmd3() { cat; }
if
cmd1 < input.txt |
cmd2 |
my_cmd3 |
cmd4 |
cmd5 |
cmd6 |
(...) |
cmdN > result.txt
Voici une solution alternative possible:
Concaténation de tuyaux nommés afin de créer un pseudo-pipeline:
dir="$(mktemp -d)"
addfifo() {
stdin="$dir/$fifo_n"
[ "$1" ] || mkfifo "$dir/$((fifo_n=fifo_n+1))"
stdout="$dir/$fifo_n"
}
addfifo; echo "The slow pink fox crawl under the brilliant dog" > "$stdout" &
# Restoring the famous line: "The quick brown fox jumps over the lazy dog"
# just replace 'true' with 'false' in any of the 5 following lines and the pseudo-pipeline will still work
true && { addfifo; sed 's/brilliant/lazy/' < "$stdin" > "$stdout" & }
true && { addfifo; sed 's/under/over/' < "$stdin" > "$stdout" & }
true && { addfifo; sed 's/crawl/jumps/' < "$stdin" > "$stdout" & }
true && { addfifo; sed 's/pink/brown/' < "$stdin" > "$stdout" & }
true && { addfifo; sed 's/slow/quick/' < "$stdin" > "$stdout" & }
addfifo -last; cat < "$stdin"
wait; rm -r "$dir"
Pour une référence future, si vous arrivez ici à la recherche de tuyaux conditionnels dans poisson, voici comment vous le faites:
set -l flags "yes"
# ...
echo "conditionalpipeline" | \
if contains -- "yes" $flags
sed "s/lp/l p/"
else
cat
end | tr '[:lower:]' '[:upper:]'