Passer deux arguments à une commande à l'aide de canaux

22

Habituellement, nous n'avons qu'à passer un argument:

echo abc | cat
echo abc | cat some_file -
echo abc | cat - some_file

Existe-t-il un moyen de passer deux arguments? Quelque chose comme

{echo abc , echo xyz} | cat
cat `echo abc` `echo xyz`

Je pourrais tout d'abord stocker les deux résultats dans un fichier

echo abc > file1
echo xyz > file2
cat file1 file2

Mais alors je pourrais accidentellement écraser un fichier, ce qui n'est pas correct. Cela entre dans un script non interactif. Fondamentalement, j'ai besoin d'un moyen de transmettre les résultats de deux commandes arbitraires à catsans écrire dans un fichier.


MISE À JOUR: Désolé, l'exemple masque le problème. Bien que { echo abc ; echo xyz ; } | catcela semble fonctionner, la sortie est due au echos, pas au cat.

Un meilleur exemple serait celui { cut -f2 -d, file1; cut -f1 -d, file2; } | paste -d,qui ne fonctionne pas comme prévu.

Avec

file1:
a,b
c,d

file2:
1,2
3,4

La sortie attendue est:

b,1
d,3

RÉSOLU:

Utilisez la substitution de processus :cat <(command1) <(command2)

Vous pouvez également créer des canaux nommés à l'aide de mkfifo:

mkfifo temp1
mkfifo temp2
command1 > temp1 &
command2 > temp2 &
cat temp1 temp2

Moins élégant et plus verbeux, mais fonctionne très bien, tant que vous vous assurez que temp1 et temp2 n'existent pas au préalable.

goweon
la source
1
Cela me fait me gratter la tête. Vous souhaitez diriger deux commandes différentes vers un seul chat?
user606723
2
Vous savez que "piping" et "arguments" sont deux concepts complètement indépendants, non?
Ignacio Vazquez-Abrams
@Ignacio euh ... Je ne connais pas très bien Linux donc je ne connais pas vraiment la différence. J'ai toujours pensé que la tuyauterie signifiait qu'elle prenait le résultat précédent comme argument. Envie de m'éclairer?
goweon
@firebat no, pipe signifie prendre la sortie standard de la commande précédente comme entrée standard de la commande suivante. Vous pouvez toujours avoir des arguments, qui sont un concept différent.
Rich Homolka
De plus, en ce qui concerne votre texte de mise à jour, la sortie provient de cat, vous voulez juste que les instructions semblent distinctes de cat, ce qu'il ne peut pas faire car elles sont sérialisées en un seul flux.
Rich Homolka

Réponses:

17

Je pense que vous voulez «Process Substitution» http://tldp.org/LDP/abs/html/process-sub.html . Il fonctionne également sur zsh, bien qu'il ait plus d'options et que la syntaxe puisse être différente.

Il crée un pseudo fichier ( /dev/fd/something) pour chaque substitution. C'est assez utile. La commande ne peut être lue que comme un flux, ce qui signifie qu'elle ne peut pas aller et venir avec fseek. Il doit le lire comme un flux d'octets, comme un tuyau.

Vos exemples fonctionnent comme substitution de processus:

cat <(echo abc) <(echo xyz)
paste -d, <(cut -f2 -d, file1) <(cut -f1 -d, file2)

Considérez-le comme un outil pour utiliser un processus et faites-le prétendre être un fichier sans aucun fichier temporaire.

(d'après ma réponse précédente )

Rich Homolka
la source
2

Le truc des accolades bouclés a réellement fonctionné parce que l'opérateur de tuyau connectera les sorties standard des commandes groupées à l'entrée standard de la troisième.

Vous pouvez dire que l'impression ne provient pas des échos en exécutant une commande qui n'utilise pas d'entrée standard, par exemple { echo 1; echo 2;} | echo 3, imprimera 3 par opposition à 1 \ n2 \ n3.

Cependant, ce n'est pas la chose que vous vouliez, car les deux commandes entre accolades écrivent sur la même sortie, ce qui revient à catcomparer leurs résultats. Pour générer deux résultats différents à utiliser comme deux arguments pour des commandes comme paste, vous devrez utiliser un fichier temporaire ou un canal nommé.

Vous pouvez utiliser mktemppour générer un fichier temporaire unique ou mkfifopour créer un fichier de canal FIFO.

billc.cn
la source
Un grand merci pour votre réponse, j'ai cherché beaucoup de jours pour cette solution et finalement trouvé votre réponse ici.
Saeed Falsafin
2

J'aime les xargs Par exemple, je veux trouver la taille de tous les répertoires de données mysql sous / usr / local

osx: utilisateur local $ pwd
/ usr / local
osx: utilisateur local $ ls | grep mysql
mysql
mysql-5.0.51a-osx10.5-x86_64
mysql-5.0.51b-osx10.5-x86_64
mysql-5.1.39-osx10.5-x86_64
mysql-5.6.17-osx10.7-x86_64
os x: utilisateur local $ ls | grep mysql | sudo xargs du -sh
4.0K mysql
2.8G mysql-5.0.51a-osx10.5-x86_64
 10G mysql-5.0.51b-osx10.5-x86_64
 25G mysql-5.1.39-osx10.5-x86_64
753M mysql-5.6.17-osx10.7-x86_64
osx: utilisateur local $ 

xargs

touche
la source