249 votes

Comment différencier les résultats de deux commandes ?

J'avais imaginé que la manière la plus simple de comparer le contenu de deux répertoires similaires serait quelque chose comme

diff `ls old` `ls new`

Mais je vois pourquoi ça ne marche pas ; diff est de recevoir une longue liste de fichiers sur la ligne de commande, plutôt que deux flux comme je l'avais espéré. Comment puis-je passer les deux sorties à diff directement ?

362voto

Schof Points 952

Substitution de commande `…` substitue la sortie de la commande dans la ligne de commande, donc diff voit la liste des fichiers dans les deux répertoires comme arguments. Ce que vous voulez, c'est que diff pour voir deux noms de fichiers sur sa ligne de commande, et que le contenu de ces fichiers soit la liste des répertoires. C'est ce que substitution de processus fait.

diff <(ls old) <(ls new)

Les arguments de diff ressemblera à /dev/fd/3 y /dev/fd/4 : ce sont des descripteurs de fichiers correspondant à deux pipes créés par bash. Lorsque diff ouvre ces fichiers, il sera connecté au côté lecture de chaque tube. Le côté écriture de chaque tube est connecté à l'objet ls commandement.

13voto

WooYek Points 229

Poisson Shell

Dans le poisson Shell, vous devez pipe dans psub . Voici un exemple de comparaison de la configuration de heroku et dokku avec Au-delà de la comparaison :

bcompare (ssh me@myapp.pl dokku config myapp | sort | psub) (heroku config -a myapp | sort | psub)

7voto

Mehdi LAMRANI Points 151

Pour zsh, utiliser =(command) crée automatiquement un fichier temporaire et remplace =(command) avec le chemin du fichier lui-même. Avec la substitution de commande, $(command) est remplacé par le sortie de la commande.

Il y a donc trois options :

  1. Substitution de commande : $(...)
  2. Substitution de processus : <(...)
  3. Substitution de processus à la sauce zsh : =(...)

La subsitution de processus à la sauce zsh, #3, est très utile et peut être utilisée ainsi pour comparer la sortie de deux commandes à l'aide d'un outil diff, par exemple Beyond Compare :

bcomp  =(ulimit -Sa | sort) =(ulimit -Ha | sort)

Pour Beyond Compare, notez que vous devez utiliser bcomp pour ce qui précède (au lieu de bcompare ) puisque bcomp lance la comparaison et attend pour qu'il soit complet. Si vous utilisez bcompare qui lance la comparaison et sort immédiatement, ce qui fait disparaître les fichiers temporaires créés pour stocker les résultats des commandes.

Plus d'informations ici : http://zsh.sourceforge.net/Intro/intro_7.html

Remarquez aussi ceci :

Notez que le Shell crée un fichier temporaire, et le supprime lorsque la commande est terminée.

et le suivant qui est la différence entre les deux types de substitution de processus supportés par zsh (c'est-à-dire #2 et #3) :

Si vous lisez la page de manuel de zsh, vous pouvez remarquer que <(...) est une autre forme de substitution de processus qui est similaire à =(...). Il y a une différence importante entre les deux. Dans le cas <(...), le Shell crée un tube nommé (FIFO) au lieu d'un fichier. C'est mieux, car cela ne remplit pas le système de fichiers ; mais cela ne fonctionne pas dans tous les cas. En fait, si nous avions remplacé =(...) par <(...) dans les exemples ci-dessus, tous auraient cessé de fonctionner, sauf fgrep -f <(...). Vous ne pouvez pas éditer un pipe, ni l'ouvrir comme un dossier de courrier ; fgrep, cependant, n'a aucun problème à lire une liste de mots à partir d'un pipe. Vous pouvez vous demander pourquoi diff <(foo) bar ne fonctionne pas, puisque foo | diff - bar fonctionne ; c'est parce que diff crée un fichier temporaire s'il remarque que l'un de ses arguments est -, et copie ensuite son entrée standard dans le fichier temporaire.

Référence : https://unix.stackexchange.com/questions/393349/difference-between-subshells-and-process-substitution

2voto

htaccess Points 1237

J'utilise souvent la technique décrite dans la réponse acceptée :

diff <(ls old) <(ls new)

mais je trouve que je l'utilise généralement avec des commandes beaucoup plus complexes que l'exemple ci-dessus. Dans de tels cas, il peut être ennuyeux d'utiliser la commande diff. J'ai trouvé quelques solutions que d'autres pourraient trouver utiles.

Je trouve que 99% du temps, j'essaie les commandes pertinentes avant de lancer diff. Par conséquent, les commandes que je veux différencier se trouvent dans mon historique... pourquoi ne pas les utiliser ?

J'utilise la commande fixe (fc) bash builtin pour exécuter les deux dernières commandes :

$ echo A
A
$ echo B
B
$ diff --color <( $(fc -ln -1 -1) ) <( $(fc -ln -2 -2 ) )
1c1
< B
---
> A

Les drapeaux fc sont :

-n : Pas de numéro. Il supprime les numéros de commande lors de l'énumération.

-l : Listing : Les commandes sont listées sur la sortie standard.

le site -1 -1 se réfèrent à la position de début et de fin dans l'historique, dans ce cas, c'est de la dernière commande à la dernière commande qui donne juste la dernière commande.

Enfin, nous enveloppons le tout dans $() pour exécuter la commande dans un sous-shell.

Il est évident que c'est un peu difficile à taper, nous pouvons donc créer un alias :

alias dl='diff --color <( $(fc -ln -1 -1) ) <( $(fc -ln -2 -2 ) )'

Ou nous pouvons créer une fonction :

dl() {
    if [[ -z "$1" ]]; then
        first="1"
    else
        first="$1"
    fi
    if [[ -z "$2" ]]; then
        last="2"
    else
        last="$2"
    fi
    # shellcheck disable=SC2091
    diff --color <( $(fc -ln "-$first" "-$first") ) <( $(fc -ln "-$last" "-$last") )
}

qui permet de spécifier les lignes d'historique à utiliser. Après avoir utilisé les deux, je trouve que l'alias est la version que je préfère.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X