Différence de chaîne dans Bash

110

J'essaie de trouver un moyen de déterminer la différence entre deux chaînes de mon script. Je pourrais facilement le faire avec diff ou comm, mais je ne m'occupe pas de fichiers et je préfère ne pas les exporter dans des fichiers, faire la comparaison et la relire.

Je vois que comm, diff, cmp permettent tous de passer soit deux fichiers, soit un fichier et une entrée standard - je suppose que c'est bien si je ne veux pas sortir deux fichiers ... mais c'est toujours un peu nul.

J'ai fouillé en pensant que je pouvais utiliser grep ou des expressions régulières - mais je suppose que non.

codeforester
la source
1
que voulez-vous vraiment faire?
Vous pouvez utiliser des manipulations de sous-chaînes et des opérations de test intégrées avec des modifications IFS pour comparer, mais vous devez savoir si vous voulez comparer caractère par caractère, mot par mot, ligne par ligne, ignorer les espaces blancs ...
technosaurus

Réponses:

198

En utilisant diffou comou ce que vous voulez:

diff  <(echo "$string1" ) <(echo "$string2")

FAQ Greg's Bash: Substitution de processus

ou avec un tube nommé

mkfifo ./p
diff - p <<< "$string1" & echo "$string2" > p

FAQ Greg's Bash: Travailler avec des tubes nommés

Le tube nommé est également connu sous le nom de FIFO.

Le -seul est pour l'entrée standard.

<<< est une "chaîne ici".

&est comme ;mais le met en arrière-plan

Ian Kelling
la source
5
+1 pour la bonne réponse. +1 pour une excellente explication des symboles. De plus, la FAQ de Greg's Bash a été déplacée vers: mywiki.wooledge.org Les liens pour les pages ci-dessus sont maintenant sur mywiki.wooledge.org/ProcessSubstitution et mywiki.wooledge.org/BashFAQ/085
timemachine3030
THX! et aussi, cela montrera les descripteurs de fichiers dynamiquesFUNC(){ echo "$@"; "$@"; }; FUNC diff <(echo a) <(echo b);
Aquarius Power
Je cherchais ça pour comparer deux shasums. Je ne sais pas s'il existe une manière plus élégante de le faire, mais cela fonctionne.
fuma
Cela semble fonctionner s'il y a plusieurs lignes dans $ string1 et $ string2, et que diff génère les lignes qui ont été ajoutées ou soustraites. Que faire si la chaîne est une seule ligne et ligne et qu'il y a une différence entre les deux chaînes?
alpha_989
@ alpha_989, voici votre réponse: l' $ diff <(echo "Here are the letters in String One.") <(echo "Here are the characters in String Two.") \n 1c1 \n < Here are the letters in String One. \n --- \n > Here are the characters in String Two. \nutilisation du tube est similaire, sauf qu'il montre un numéro de processus, commence par 1c1après le suivant $et attend que vous appuyiez sur <kbd> Entrée <kbd> (ou vous pouvez faire d'autres commandes ...)
bballdave025
19

Cela me rappelle cette question: comment pouvez-vous différencier deux pipelines dans Bash?

Si vous êtes dans une session bash, vous pouvez faire un:

diff <cmd1 <cmd2
diff <(foo | bar) <(baz | quux)

avec la <création de tubes nommés anonymes - gérés par bash - afin qu'ils soient créés et détruits automatiquement, contrairement aux fichiers temporaires.

Donc si vous parvenez à isoler vos deux chaînes différentes dans le cadre d'une commande (grep, awk, sed, ...), vous pouvez faire - par exemple - quelque chose comme:

diff < grep string1 myFile < grep string2 myFile

(si vous supposez avoir dans votre fichier des lignes comme string1=very_complicated_valueet a string2=another_long_and_complicated_value': sans connaître le format interne de votre fichier, je ne peux pas recommander une commande précise)

VonC
la source
13

Je préfère cmpet la fonction de substitution de processus de bash:

$ cmp -bl <(echo -n abcda) <(echo -n aqcde)
  2 142 b    161 q
  5 141 a    145 e

En disant à la position 2, ab se produit pour le premier, mais aq pour le second. En position 5, une autre différence se produit. Remplacez simplement ces chaînes par des variables, et vous avez terminé.

Johannes Schaub - litb
la source
Cela ne fonctionne que lorsque les chaînes sont de la même longueur!
strpeter
11

Disons que vous avez trois chaînes

a="this is a line"
b="this is"
c="a line"

Pour supprimer le préfixe b d'un

echo ${a#"$b"}  # a line

Pour supprimer le suffixe c d'un

echo ${a%"$c"}  # this is
Pithikos
la source
2
Je suppose que c'est la façon la plus simple de le faire. Cela a bien fonctionné. Cette syntaxe est cependant un peu difficile à comprendre.
Mikael Roos
@MikaelRoos D'accord. Plus facile à lire (pour moi en tout cas) serait d'utiliser sed: echo "$a" | sed "s!^$b!!g" (j'ai échangé le séparateur sed standard / pour! Au cas où les variables traitées sont des chemins. De plus, vous pouvez utiliser une chaîne ici au lieu de echo:. sed ... <<< $a)
ACK_stoverflow
1

Un autre exemple:

before="184613 102050 83756 63054"
after="184613 102050 84192 83756 63054"

comm -23 <(tr ' ' $'\n' <<< $after | sort) <(tr ' ' $'\n' <<< $before | sort)

Les sorties

84192

Réponse originale ici

Sida Zhou
la source