Bash'de dize farkı


110

Senaryomdaki iki dizge arasındaki farkı belirlemenin bir yolunu bulmaya çalışıyorum. Bunu diff veya comm ile kolayca yapabilirim, ancak dosyalarla uğraşmıyorum ve onları dosyalara çıkarmayı, karşılaştırmayı yapıp geri okumayı tercih ederim.

Comm, diff, cmp'nin ya iki dosyayı VEYA bir dosyayı ve standart girdiyi geçmesine izin verdiğini görüyorum - sanırım iki dosya çıkarmak istemiyorsam iyi olur ... ama yine de biraz berbat.

Grep veya normal ifadeler kullanabileceğimi düşünerek etrafı araştırıyorum - ama sanmıyorum.


1
aslında yapmak istediğin şey nedir?

Karşılaştırmak için IFS değişiklikleriyle alt dize işlemlerini ve yerleşik test işlemlerini kullanabilirsiniz, ancak karakter bazında, kelimeye göre, satır satır karşılaştırmak, beyaz boşluğu yok saymak isteyip istemediğinizi bilmeniz gerekir ...
technosaurus

Yanıtlar:


198

Kullanmak diffveya comveya ne istersen:

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

Greg's Bash SSS: İşlem Değiştirme

veya adlandırılmış bir boru ile

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

Greg's Bash SSS: Adlandırılmış Borularla Çalışma

Adlandırılmış kanal aynı zamanda FIFO olarak da bilinir.

Tek -başına standart giriş içindir.

<<< bir "burada dizesi" dir.

&gibidir ;ama arka plana koyar


5
Doğru cevap için +1. Sembollerin harika açıklaması için +1. Ek olarak, Greg's Bash SSS şu adrese taşındı: mywiki.wooledge.org Yukarıdaki sayfaların bağlantıları artık mywiki.wooledge.org/ProcessSubstitution ve mywiki.wooledge.org/BashFAQ/085
timemachine3030

Teşekkürler! ve ayrıca dinamik dosya tanımlayıcılarını gösterecekFUNC(){ echo "$@"; "$@"; }; FUNC diff <(echo a) <(echo b);
Aquarius Power

Bunu iki shasumu karşılaştırmak için arıyordum. Bunu yapmanın daha zarif bir yolu olup olmadığından emin değilim, ama işe yarıyor.
fuma

Bu, $ dizge1 ve $ dizge2'de birden çok satır varsa ve diff eklenen veya çıkarılan satırları çıktılarsa işe yarıyor gibi görünüyor. Ya dize tek bir satır ve bir satırsa ve iki dizge arasında bir miktar fark varsa?
alpha_989

@ alpha_989, cevabınız burada: $ 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. \nBoru kullanmak benzerdir, ancak bir işlem numarası gösterir, bir 1c1sonrakinden sonra başlar $ve <kbd> Enter <kbd> tuşuna basana kadar bekler (veya başka komutlar yapabilirsiniz ...)
bballdave025

19

Bana şu soruyu hatırlatıyor: Bash'de iki ardışık düzeni nasıl ayırt edebilirsiniz?

Bir bash oturumundaysanız, şunları yapabilirsiniz:

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

ile <bash tarafından yönetilen - - yarattıkları ve geçici dosyaları aksine otomatik yok edildiği şekilde anonim adlandırılmış yöneltme yaratır.

Dolayısıyla, iki farklı dizenizi bir komutun parçası olarak (grep, awk, sed, ...) izole etmeyi başarırsanız, örneğin - aşağıdakilere benzer bir şey yapabilirsiniz:

diff < grep string1 myFile < grep string2 myFile

(Dosya satırlarınızda string1=very_complicated_valueve a string2=another_long_and_complicated_value': gibi dosya satırlarınız olduğunu düşünüyorsanız, dosyanızın iç biçimini bilmeden kesin bir komut öneremem)


13

cmpBash'in Süreci Değiştirme özelliğini tercih ediyorum :

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

2. pozisyonda diyerek, birinci için ab, ikincisi için aq vardır. 5. pozisyonda başka bir farklılık oluyor. Sadece bu dizeleri değişkenlerle değiştirin ve bitirdiniz.


Bu, yalnızca dizeler aynı uzunlukta olduğunda çalışır!
strpeter

11

Üç telin olduğunu söyle

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

A önekini kaldırmak için

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

A'dan c sonekini kaldırmak için

echo ${a%"$c"}  # this is

2
Sanırım bunu yapmanın en iyi yolu bu. Güzel çalıştı. Yine de bu sözdizimini kavramak biraz zor.
Mikael Roos

@MikaelRoos Kabul edildi. : Sed kullanmak (zaten benim için) okumak için daha kolay olurdu echo "$a" | sed "s!^$b!!g" (!. Ben durumda yönelik değişkenler ile yolları vardır Ayrıca dağıtım yapılmadan standart / sed ayırıcı takas yerine yankı bir buraya dize kullanabilirsiniz: sed ... <<< $a.)
ACK_stoverflow

1

Başka bir örnek:

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

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

çıktılar

84192

Orijinal cevap burada

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.