Perbedaan string di Bash

110

Saya mencoba menemukan cara untuk menentukan perbedaan antara dua string dalam skrip saya. Saya dapat dengan mudah melakukan ini dengan diff atau comm, tetapi saya tidak berurusan dengan file dan saya lebih suka untuk tidak menampilkannya ke file, melakukan perbandingan dan membacanya kembali.

Saya melihat bahwa comm, diff, cmp semuanya memungkinkan untuk melewatkan dua file ATAU file dan input standar - saya rasa itu bagus jika saya tidak ingin mengeluarkan dua file ... tapi masih agak menyebalkan.

Telah menggali sekitar berpikir saya bisa menggunakan grep atau ekspresi reguler - tapi saya rasa tidak.

codeforester
sumber
1
apa yang sebenarnya ingin kamu lakukan?
Anda dapat menggunakan manipulasi substring dan operasi pengujian bawaan dengan perubahan IFS untuk membandingkan, tetapi Anda perlu mengetahui apakah Anda ingin membandingkan karakter demi karakter, kata demi kata, baris demi baris, mengabaikan spasi putih ...
technosaurus

Jawaban:

198

Menggunakan diffatau comatau apapun yang Anda inginkan:

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

Tanya Jawab Greg's Bash: Pergantian Proses

atau dengan pipa bernama

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

Greg's Bash FAQ: Bekerja dengan Named Pipes

Pipa bernama juga dikenal sebagai FIFO.

The -sendiri adalah untuk input standar.

<<< adalah "string di sini".

&seperti ;tetapi meletakkannya di latar belakang

Ian Kelling
sumber
5
1 untuk jawaban yang benar. 1 untuk penjelasan simbol yang bagus. Selain itu, FAQ Greg Bash telah pindah ke: mywiki.wooledge.org Tautan untuk halaman di atas sekarang ada di mywiki.wooledge.org/ProcessSubstitution dan mywiki.wooledge.org/BashFAQ/085
timemachine3030
Terima kasih! dan juga, ini akan menampilkan deskriptor file dinamisFUNC(){ echo "$@"; "$@"; }; FUNC diff <(echo a) <(echo b);
Aquarius Power
Saya mencari itu untuk membandingkan dua syasum. Tidak yakin apakah ada cara yang lebih elegan untuk melakukan itu, tetapi berhasil.
fuma
Ini tampaknya berfungsi jika ada beberapa baris dalam $ string1 dan $ string2, dan diff menghasilkan baris yang ditambahkan atau dikurangi. Bagaimana jika string adalah satu baris, dan baris dan ada beberapa perbedaan antara kedua string tersebut?
alpha_989
@ alpha_989, inilah jawaban Anda: $ 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. \nMenggunakan pipa serupa, kecuali itu menunjukkan nomor proses, dimulai dengan 1c1setelah berikutnya $, dan menunggu sampai Anda menekan <kbd> Enter <kbd> (atau Anda dapat melakukan perintah lain ...)
bballdave025
19

Mengingatkan saya pada pertanyaan ini: Bagaimana Anda bisa membedakan dua jalur pipa di Bash?

Jika Anda berada dalam sesi bash, Anda bisa melakukan:

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

dengan <membuat pipa bernama anonim - dikelola oleh bash - sehingga dibuat dan dihancurkan secara otomatis, tidak seperti file sementara.

Jadi jika Anda berhasil mengisolasi dua string berbeda sebagai bagian dari perintah (grep, awk, sed, ...), Anda dapat melakukan - misalnya - sesuatu seperti:

diff < grep string1 myFile < grep string2 myFile

(jika Anda mengira Anda memiliki baris file seperti string1=very_complicated_valuedan string2=another_long_and_complicated_value': tanpa mengetahui format internal file Anda, saya tidak dapat merekomendasikan perintah yang tepat)

VonC
sumber
13

Saya lebih suka cmpdan fitur Proses Substitusi bash:

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

Mengatakan pada posisi 2, ab muncul untuk yang pertama, tetapi aq untuk yang kedua. Di posisi 5, perbedaan lain terjadi. Cukup ganti string tersebut dengan variabel, dan Anda selesai.

Johannes Schaub - litb
sumber
Ini hanya berfungsi jika string memiliki panjang yang sama!
strpeter
11

Katakanlah Anda memiliki tiga senar

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

Untuk menghapus prefiks b dari a

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

Untuk menghapus sufiks c dari a

echo ${a%"$c"}  # this is
Pithikos
sumber
2
Saya kira ini adalah cara bash untuk melakukannya. Ini bekerja dengan baik. Sintaks itu agak sulit dipahami.
Mikael Roos
@MikaelRoos Setuju. Lebih mudah untuk membaca (untuk saya sih) akan menggunakan sed: echo "$a" | sed "s!^$b!!g" (Saya menukar pemisah sed standar / untuk! Jika variabel yang ditangani adalah jalur. Selain itu, Anda dapat menggunakan string di sini daripada echo:. sed ... <<< $a)
ACK_stoverflow
1

Contoh lain:

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

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

Keluaran

84192

Jawaban asli di sini

Sida Zhou
sumber