Une fonction shell. Cela fonctionnera dans n'importe quel shell prenant en charge <<<
chaînes ici, y compris zsh et bash.
xyz() {
while read line
do
printf "%s " "$line"
"[email protected]" <<<"$line"
done
}
$ (echo "foo"; echo "bar") | xyz rev
foo oof
bar rab
Il y aura beaucoup de problèmes dans la plupart des cas en raison du fonctionnement de la mise en mémoire tampon stdio. Une solution de contournement pour Linux pourrait être d'utiliser le stdbuf
programmez et exécutez la commande avec coproc, afin que vous puissiez contrôler explicitement l'entrelacement de la sortie.
Ce qui suit suppose que la commande affichera une ligne après chaque ligne d'entrée.
#!/bin/bash
coproc stdbuf -i0 -o0 "[email protected]"
IFS=
while read -r in ; do
printf "%s " "$in"
printf "%s\n" "$in" >&${COPROC[1]}
read -r out <&${COPROC[0]}
printf "%s\n" "$out"
done
Si une solution plus générale est nécessaire car l'OP ne nécessitait que chaque ligne d'entrée du programme pour éventuellement sortie une ligne plutôt qu'immédiatement, alors une approche plus compliquée est nécessaire. Créer une boucle d'événement en utilisant read -t 0
pour essayer de lire à partir de stdin et du co-processus, si vous avez le même "numéro de ligne" pour les deux, sortez, sinon stockez la ligne. Pour éviter d'utiliser 100 % du processeur si, à aucun tour de la boucle d'événements, aucun n'était prêt, introduisez un petit délai avant d'exécuter à nouveau la boucle d'événements. Il y a des complications supplémentaires si le processus génère des lignes partielles, celles-ci doivent être mises en mémoire tampon.
Si cette solution plus générale est nécessaire, j'écrirais ceci en utilisant expect car elle prend déjà bien en charge la gestion de la correspondance de modèles sur plusieurs flux d'entrée. Cependant, ce n'est pas une solution bash/zsh.
Dans ce cas particulier, j'utiliserais perl
:
printf '%s\n' foo bar | perl -Mopen=locale -lpe '$_ .= " " . reverse$_'
foo oof
bar rab
Que vous pourriez étendre pour travailler également avec des clusters de graphèmes :
$ printf '%s\n' $'complique\u301' |
perl -Mopen=locale -lpe '$_ .= " " . join "", reverse/\X/g'
compliqué éuqilpmoc
Ou zsh
:
while IFS= read -r line; do
print -r -- $line ${(j::)${(s::Oa)line}}
done
Bien que j'éviterais d'utiliser while read
boucles pour traiter du texte, même en zsh
(même si dans ce cas particulier, ce n'est pas si mal car seules les commandes intégrées sont utilisées).
Dans le cas général, l'utilisation de fichiers temporaires est probablement la meilleure approche. Avec zsh
, vous pouvez le faire avec :
(){paste -d ' ' $1 <(rev <$1)} =(print -l foo bar)
(où =(...)
se charge de créer et de nettoyer le fichier temporaire).
Le remplacer par des tuyaux et une forme de tee
ing est une recette pour l'impasse dans le cas général. Consultez ces questions similaires pour certaines approches et des détails sur les situations de blocage :
- Diviser une entrée pour différentes commandes et combiner le résultat
- tee + cat :utiliser une sortie plusieurs fois puis concaténer les résultats