Il y a certaines commandes qui filtrent ou agissent sur l'entrée, puis la transmettent en sortie, je pense généralement à stdout
- mais certaines commandes prendront simplement le stdin
et feront tout ce qu'elles feront avec et ne rien produire.
Je connais le mieux OS X et il y en a donc deux qui me viennent immédiatement à l'esprit: pbcopy
et pbpaste
- qui sont des moyens d'accéder au presse-papiers du système.
Quoi qu'il en soit, je sais que si je veux prendre stdout et cracher la sortie pour aller à la fois à stdout
et à un fichier, je peux utiliser la commande tee
. Et je connais un peu xargs
, mais je ne pense pas que ce soit ce que je recherche.
Je veux savoir comment je peux diviser stdout
pour passer entre deux (ou plus) commandes. Par exemple:
cat file.txt | stdout-split -c1 pbcopy -c2 grep -i errors
Il y a probablement un meilleur exemple que celui-ci, mais je suis vraiment intéressé de savoir comment envoyer stdout à une commande qui ne la relaie pas et tout en empêchant stdout
d'être "muet" - je ne demande pas comment cat
un fichier et grep
une partie de celui-ci et le copier dans le presse-papiers - les commandes spécifiques ne sont pas si importantes.
Aussi - je ne demande pas comment envoyer ceci dans un fichier et stdout
- cela peut être une question "en double" (désolé) mais j'ai fait quelques recherches et n'ai pu trouver que des questions similaires qui demandaient comment divisé entre stdout et un fichier - et les réponses à ces questions semblaient être tee
, ce qui, je pense, ne fonctionnera pas pour moi.
Enfin, vous pouvez vous demander "pourquoi ne pas simplement faire de pbcopy la dernière chose dans la chaîne de tuyaux?" et ma réponse est 1) et si je veux l'utiliser et voir toujours la sortie dans la console? 2) que faire si je veux utiliser deux commandes qui ne produisent pas stdout
après avoir traité l'entrée?
Oh, et encore une chose - je me rends compte que je pourrais utiliser tee
et un canal nommé (mkfifo
) mais j'espérais que cela pourrait être fait en ligne, de manière concise, sans configuration préalable: )
Vous pouvez utiliser tee
et effectuer une substitution de processus pour cela:
cat file.txt | tee >(pbcopy) | grep errors
Cela enverra toute la sortie de cat file.txt
à pbcopy
, et vous n'aurez que le résultat de grep
sur votre console.
Vous pouvez placer plusieurs processus dans la partie tee
:
cat file.txt | tee >(pbcopy) >(do_stuff) >(do_more_stuff) | grep errors
Vous pouvez spécifier plusieurs noms de fichiers sur tee
et, en outre, la sortie standard peut être canalisée dans une seule commande. Pour répartir la sortie vers plusieurs commandes, vous devez créer plusieurs canaux et spécifier chacun d'eux comme une sortie de tee
. Il y a plusieurs moyens de le faire.
Si votre Shell est ksh93, bash ou zsh, vous pouvez utiliser la substitution de processus. Il s'agit d'un moyen de passer un canal à une commande qui attend un nom de fichier. Le shell crée le canal et passe un nom de fichier comme /dev/fd/3
à la commande. Le nombre est le descripteur de fichier auquel le tuyau est connecté. Certaines variantes Unix ne prennent pas en charge /dev/fd
; sur ceux-ci, un tube nommé est utilisé à la place (voir ci-dessous).
tee >(command1) >(command2) | command3
Dans n'importe quel shell POSIX, vous pouvez utiliser plusieurs descripteurs de fichiers explicitement. Cela nécessite une variante Unix qui prend en charge /dev/fd
, car toutes les sorties de tee
sauf une doivent être spécifiées par leur nom.
{ { { tee /dev/fd/3 /dev/fd/4 | command1 >&9;
} 3>&1 | command2 >&9;
} 4>&1 | command3 >&9;
} 9>&1
La méthode la plus simple et la plus portable consiste à utiliser tubes nommés . L'inconvénient est que vous devez trouver un répertoire accessible en écriture, créer les canaux et nettoyer ensuite.
tmp_dir=$(mktemp -d)
mkfifo "$tmp_dir/f1" "$tmp_dir/f2"
command1 <"$tmp_dir/f1" & pid1=$!
command2 <"$tmp_dir/f2" & pid2=$!
tee "$tmp_dir/f1" "$tmp_dir/f2" | command3
rm -rf "$tmp_dir"
wait $pid1 $pid2
Jouez avec la substitution de processus.
mycommand_exec |tee >(grep ook > ook.txt) >(grep eek > eek.txt)
grep
sont deux binaires qui ont la même sortie de mycommand_exec
comme entrée spécifique au processus.
Si vous utilisez zsh
, vous pouvez profiter de la puissance de la fonction MULTIOS
, c'est-à-dire se débarrasser complètement de la commande tee
:
uname >file1 >file2
va simplement écrire la sortie de uname
dans deux fichiers différents: file1
et file2
, ce qui équivaut à uname | tee file1 >file2
Redirection similaire des entrées standard
wc -l <file1 <file2
est équivalent à cat file1 file2 | wc -l
(veuillez noter que ce n'est pas la même chose que wc -l file1 file2
, la dernière compte séparément le nombre de lignes de chaque fichier).
Bien sûr, vous pouvez également utiliser MULTIOS
pour rediriger la sortie non pas vers des fichiers mais vers d'autres processus, en utilisant la substitution de processus, par exemple:
echo abc > >(grep -o a) > >(tr b x) > >(sed 's/c/y/')
Pour une sortie raisonnablement petite produite par une commande, nous pouvons rediriger la sortie vers un fichier temporaire et envoyer ces fichiers temporaires aux commandes en boucle. Cela peut être utile lorsque l'ordre des commandes exécutées peut être important.
Le script suivant, par exemple, pourrait le faire:
#!/bin/sh
temp=$( mktemp )
cat /dev/stdin > "$temp"
for arg
do
eval "$arg" < "$temp"
done
rm "$temp"
Test exécuté sur Ubuntu 16.04 avec /bin/sh
as dash
Shell:
$ cat /etc/passwd | ./multiple_pipes.sh 'wc -l' 'grep "root"'
48
root:x:0:0:root:/root:/bin/bash
Capturez la commande STDOUT
dans une variable et réutilisez-la autant de fois que vous le souhaitez:
commandoutput="$(command-to-run)"
echo "$commandoutput" | grep -i errors
echo "$commandoutput" | pbcopy
Si vous devez également capturer STDERR
, utilisez 2>&1
à la fin de la commande, comme ceci:
commandoutput="$(command-to-run 2>&1)"
Cela peut être utile: http://www.spinellis.gr/sw/dgsh/ (shell graphique orienté) On dirait un remplacement bash supportant une syntaxe plus facile pour les commandes "multipipe".
Voici une solution partielle rapide et sale, compatible avec n'importe quel shell, y compris busybox
.
Le problème le plus étroit qu'il résout est: imprimer le stdout
complet sur une console et le filtrer sur une autre, sans fichiers temporaires ni canaux nommés.
tty
. Assumons /dev/pty/2
.the_program | tee /dev/pty/2 | grep ImportantLog:
Vous obtenez un journal complet et un journal filtré.