Fractionner une entrée pour une commande différente et combiner le résultat

8

Je sais combiner le résultat de différentes commandes

paste -t',' <(commanda) <(commandb)

Je sais diriger la même entrée vers une commande différente

cat myfile | tee >(commanda) >(commandb)

Maintenant, comment combiner ces commandes? Pour que je puisse faire

cat myfile | tee >(commanda) >(commandb) | paste -t',' resulta resultb

Dis que j'ai un fichier

mon fichier:

1
2
3
4

Je veux créer un nouveau fichier

1 4 2
2 3 4
3 2 6
4 1 8

j'ai utilisé

cat myfile | tee >(tac) >(awk '{print $1*2}') | paste

me donnerait un résultat vertical, où je veux vraiment les coller dans l'ordre horizontal.

user40129
la source
vous devrez peut-être écrire deux flux pour séparer les canaux de noms et les combiner avec un programme de surveillance.
把 友情 留 在 无 盐

Réponses:

8

Lorsque vous effectuez plusieurs substitutions de processus, vous n'êtes pas assuré d'obtenir la sortie dans un ordre particulier, vous devriez donc vous en tenir à

paste -t',' <(commanda < file) <(commandb < file)

En supposant que cela cat myfilereprésente un pipeline coûteux, je pense que vous devrez stocker la sortie, dans un fichier ou une variable:

output=$( some expensive pipeline )
paste -t',' <(commanda <<< "$output") <(commandb <<< "$output")

En utilisant votre exemple:

output=$( seq 4 )
paste -d' ' <(cat <<<"$output") <(tac <<<"$output") <(awk '$1*=2' <<<"$output")
1 4 2
2 3 4
3 2 6
4 1 8

Une autre pensée: les FIFO et un pipeline unique

mkfifo resulta resultb
seq 4 | tee  >(tac > resulta) >(awk '$1*=2' > resultb) | paste -d ' ' - resulta resultb
rm resulta resultb
1 4 2
2 3 4
3 2 6
4 1 8
glenn jackman
la source
puis-je utiliser qch comme / dev / fd / 3-9?
user40129
4

Le yashshell possède des fonctionnalités uniques ( redirection de pipeline et redirection de processus ) qui facilitent cela:

cat myfile | (
  exec 3>>|4
  tee /dev/fd/5 5>(commanda >&3 3>&-) 3>&- |
    commandb 3>&- |
    paste -d , /dev/fd/4 - 3>&-
)

3>>|4( redirection de pipeline ) crée un canal où l'extrémité d'écriture est sur fd 3 et l'extrémité de lecture sur fd 4.

3>(commanda>&3)est la redirection de processus , un peu comme la substitution de processus ksh / zsh / bash mais fait juste la redirection et ne se substitue pas avec le /dev/fd/n. kshs >(cmd)est plus ou moins le même que yashs n>(cmd) /dev/fd/n(il ny a un descripteur de fichier choisi par kshlequel vous n'avez aucun contrôle).

Stéphane Chazelas
la source
3

Avec zsh:

pee() (
  n=0 close_in= close_out= inputs=() outputs=()
  merge_command=$1; shift
  for cmd do
    eval "coproc $cmd $close_in $close_out"

    exec {i}<&p {o}>&p
    inputs+=($i) outputs+=($o)
    eval i$n=$i o$n=$o
    close_in+=" {i$n}<&-" close_out+=" {o$n}>&-"
    ((n++))
  done
  coproc :
  read -p
  eval tee /dev/fd/$^outputs $close_in "> /dev/null &
    " exec $merge_command /dev/fd/$^inputs $close_out
)

Ensuite, utilisez comme:

$ echo abcd | pee 'paste -d,' 'tr a A' 'tr b B' 'tr c C'
Abcd,aBcd,abCd

C'est adapté de cette autre question où vous trouverez des explications détaillées et des conseils sur les limites (méfiez-vous des blocages!).

Stéphane Chazelas
la source
0

Pour votre exemple particulier, il ne devrait pas être nécessaire pasteet le reste. Il est souvent vrai que lorsque nous rencontrons une limite avec l'ensemble d'outils standard, c'est parce que ce que nous voulons faire d'une manière peut être fait d'une autre. Tel que:

set 1 2 3 4
while [ "$#" -gt 0 ]
do    echo "$1" "$#" "$(($1*2))"
shift;done

... qui imprime ...

1 4 2
2 3 4
3 2 6
4 1 8

Vous pouvez obtenir un fichier avec un contenu comme vous le mentionnez dans votre "$@"tableau shell comme ...

set -f; IFS='
'; set -- $(cat)

Et pour valider les valeurs d'arg dans une boucle comme celle ci-dessus, vous pouvez modifier un peu le test initial ...

while { [ "$1" -eq "${1-1}" ] ;} 2>&"$((2+!$#))"
do    echo "$1" "$#" "$(($1*2))"
shift;done  3>/dev/null >outfile

... qui affiche une erreur sur stderr uniquement si une ligne lue avec set -- $(cat)contient une ligne qui n'est pas entièrement composée d'un seul entier.

mikeserv
la source