Comment pouvez-vous diff deux pipelines en Bash?
Comment pouvez-vous diff deux conduites sans l'aide de fichiers temporaires en Bash? Disons que vous avez deux commande des pipelines:
foo | bar
baz | quux
Et vous voulez trouver le diff
dans leurs sorties. Une solution serait évidemment de:
foo | bar > /tmp/a
baz | quux > /tmp/b
diff /tmp/a /tmp/b
Est-il possible de le faire sans l'utilisation de fichiers temporaires en Bash? Vous pouvez vous débarrasser de l'un fichier temporaire par la tuyauterie dans l'un des pipelines de diff:
foo | bar > /tmp/a
baz | quux | diff /tmp/a -
Mais vous ne pouvez pas la pipe de deux pipelines dans diff simultanément (pas en aucune façon évidente, au moins). Est-il une astuce impliquant /dev/fd
de le faire sans l'aide de fichiers temporaires?
Vous devez vous connecter pour publier un commentaire.
Une ligne avec 2 fichiers tmp (pas ce que vous voulez) serait:
Avec bash, vous pouvez essayer de bien:
La 2ème version plus clairement, de vous rappeler d'entrée qui était qui, en montrant
-- /dev/stdin
vs++ /dev/fd/63
ou quelque chose, au lieu de deux numérotée fds.Même pas un tube nommé apparaîtra dans le système de fichiers, au moins sur les Systèmes d'exploitation où bash peuvent mettre en place des processus de substitution en utilisant des noms de fichiers comme
/dev/fd/63
pour obtenir un nom de fichier qui peuvent s'ouvrir et lire à partir de réellement lire à partir d'un descripteur de fichier ouvert que bash mis en place avant exec avec la commande. (c'est à dire bash utilisepipe(2)
avant de la fourche, puisdup2
rediriger la sortie dequux
à une entrée descripteur de fichier pourdiff
, sur fd 63.)Sur un système sans "magique"
/dev/fd
ou/proc/self/fd
, bash peut utiliser des canaux nommés pour mettre en place des processus de substitution, mais il serait au moins de les gérer lui-même, à la différence des fichiers temporaires, et vos données ne serait pas écrit pour le système de fichiers.Vous pouvez vérifier comment bash met en œuvre le processus de substitution avec
echo <(true)
pour imprimer le nom de fichier au lieu de le lire. Il imprime/dev/fd/63
sur un système Linux. Ou pour plus de détails sur exactement ce que les appels système bash utilise, cette commande sur un système Linux trace de fichiers et les fichiers système de descripteurs des appelsSans bash, vous pourriez faire un pipe nommé. Utilisation
-
dirediff
pour lire une entrée à partir de STDIN, et d'utiliser le canal nommé comme les autres:Notez que vous ne pouvez pipe une sortie à plusieurs entrées avec la commande tee:
La commande ci-dessus affiche la sortie de ls *.txt pour le terminal et sorties dans le fichier texte txtlist.txt.
Mais avec des processus de substitution, vous pouvez utiliser
tee
à nourrir les mêmes données dans plusieurs pipelines:mkfifo a; cmd >a& cmd2|diff a -; rm a
pipeline1 | diff -u - <(pipeline2)
. Ensuite, la sortie sera plus clairement, de vous rappeler d'entrée qui était qui, en montrant-- /dev/stdin
vs++ /dev/fd/67
ou quelque chose, au lieu de deux numérotée fds.foo <( pipe )
) ne pas modifier le système de fichiers. Le tuyau est anonyme; il n'a pas de nom dans le système de fichiers. Le shell utilise lapipe
appel système pour créer, pasmkfifo
. Utilisationstrace -f -efile,desc,clone,execve bash -c '/bin/true | diff -u - <(/bin/true)'
de fichier de trace et de fichiers-système de descripteurs des appels si vous voulez voir par vous-même. Sur Linux,/dev/fd/63
fait partie de la/proc
de système de fichiers virtuel; il a automatiquement des entrées pour chaque descripteur de fichier, et ce n'est pas une copie du contenu. Donc vous ne pouvez pas appeler cela un "fichiers temporaires" à moins quefoo 3<bar.txt
compteEn bash, vous pouvez utiliser des sous-coquille, pour exécuter la commande des pipelines individuellement, en joignant le pipeline à l'intérieur de la parenthèse. Vous pouvez ensuite préfixe ces avec < créer nommé anonyme tuyaux que vous pouvez ensuite passer à la diff.
Par exemple:
Anonyme, les canaux sont gérés par bash de sorte qu'ils sont créés et détruits automatiquement (contrairement aux fichiers temporaires).
Certaines personnes arrivent à cette page pourrait être la recherche d'une ligne-par-ligne de diff, pour qui
comm
ougrep -f
devrait être utilisé à la place.Une chose à noter est que, dans l'ensemble de la réponse d'exemples, les comparaisons ne sera pas réellement démarrer jusqu'à ce que les deux volets ont fini. Tester avec par exemple:
Si c'est un problème, vous pouvez essayer de sd (flux de diff), qui ne nécessitent pas de tri (comme
comm
n'), ni les processus de substitution comme les exemples ci-dessus, est des ordres de grandeur plus rapide quegrep -f
et prend en charge les flux infinis.L'exemple de test que je propose devrait être écrit comme cela dans
sd
:Mais la différence est que
seq 100
serait comparable avecseq 10
tout de suite. Notez que, si l'un des cours d'eau est untail -f
, la comparaison ne peut être fait avec le processus de substitution.Voici un article sur le blog j'ai écrit sur la comparaison des flux sur le terminal, qui introduit
sd
.