ความแตกต่างของสตริงใน Bash


110

ฉันกำลังพยายามหาวิธีกำหนดความแตกต่างระหว่างสองสตริงในสคริปต์ของฉัน ฉันสามารถทำได้อย่างง่ายดายด้วย diff หรือ comm แต่ฉันไม่ได้จัดการกับไฟล์และฉันไม่ต้องการส่งออกไปยังไฟล์ทำการเปรียบเทียบและอ่านกลับ

ฉันเห็นว่า comm, diff, cmp ทั้งหมดอนุญาตให้ส่งไฟล์สองไฟล์หรือไฟล์และอินพุตมาตรฐาน - ฉันเดาว่าดีถ้าฉันไม่ต้องการส่งออกสองไฟล์ ... แต่มันก็ยังแย่อยู่

ฉันคิดว่าฉันสามารถใช้ grep หรือนิพจน์ทั่วไป - แต่ฉันเดาว่าไม่


1
คุณอยากทำอะไร?

คุณสามารถใช้การปรับแต่งสตริงย่อยและการดำเนินการทดสอบในตัวกับการเปลี่ยนแปลงของ IFS เพื่อเปรียบเทียบได้ แต่คุณจำเป็นต้องรู้ว่าคุณต้องการเปรียบเทียบอักขระทีละตัวอักษรทีละคำทีละบรรทัดหรือไม่ละเว้นช่องว่าง ...
technosaurus

คำตอบ:


198

ใช้diffหรือcomหรือสิ่งที่คุณต้องการ:

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

คำถามที่พบบ่อยของ Greg's Bash: การทดแทนกระบวนการ

หรือท่อที่มีชื่อ

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

คำถามที่พบบ่อยของ Greg's Bash: การทำงานกับท่อที่มีชื่อ

ท่อที่มีชื่อเรียกอีกอย่างว่า FIFO

ด้วย-ตัวมันเองสำหรับอินพุตมาตรฐาน

<<< คือ "สตริงที่นี่"

&เหมือน;แต่วางไว้เบื้องหลัง


5
+1 สำหรับคำตอบที่ถูกต้อง +1 สำหรับคำอธิบายที่ดีเกี่ยวกับสัญลักษณ์ นอกจากนี้คำถามที่พบบ่อยของ Greg's Bash ได้ย้ายไปที่: mywiki.wooledge.orgลิงก์สำหรับหน้าดังกล่าวอยู่ที่mywiki.wooledge.org/ProcessSubstitutionและmywiki.wooledge.org/BashFAQ/085
timemachine3030

ขอบคุณ! และสิ่งนี้จะแสดงตัวบอกไฟล์ไดนามิกFUNC(){ echo "$@"; "$@"; }; FUNC diff <(echo a) <(echo b);
Aquarius Power

ฉันกำลังมองหาสิ่งนั้นสำหรับการจับคู่ shasums สองอัน ไม่แน่ใจว่ามีวิธีที่หรูหรากว่านี้ไหม แต่ได้ผล
fuma

ดูเหมือนว่าจะใช้งานได้ถ้ามีหลายบรรทัดใน $ string1 และ $ string2 และแตกต่างกันจะส่งออกบรรทัดที่ถูกเพิ่มหรือลบ จะเกิดอะไรขึ้นถ้าสตริงเป็นบรรทัดเดียวและบรรทัดและมีความแตกต่างบางอย่างระหว่างสตริงทั้งสอง
alpha_989

@ alpha_989 นี่คือคำตอบของคุณ: $ 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. \nการใช้ไปป์จะคล้ายกันยกเว้นจะแสดงหมายเลขกระบวนการเริ่มต้นด้วย1c1หลังจากถัดไป$และรอจนกว่าคุณจะกด <kbd> Enter <kbd> (หรือคุณสามารถทำคำสั่งอื่น ๆ ... )
bballdave025

19

ทำให้ฉันนึกถึงคำถามนี้: คุณจะแตกต่างท่อสองท่อใน Bash ได้อย่างไร?

หากคุณอยู่ในช่วงทุบตีคุณสามารถทำสิ่งต่อไปนี้

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

ด้วย<การสร้างไปป์ที่ไม่ระบุชื่อ - จัดการโดย bash - ดังนั้นจึงถูกสร้างและทำลายโดยอัตโนมัติซึ่งแตกต่างจากไฟล์ชั่วคราว

ดังนั้นหากคุณจัดการแยกสตริงที่แตกต่างกันสองสตริงของคุณเป็นส่วนหนึ่งของคำสั่ง (grep, awk, sed, ... ) คุณสามารถทำได้ - ตัวอย่างเช่น:

diff < grep string1 myFile < grep string2 myFile

(ถ้าคุณคิดว่าคุณมีในบรรทัดไฟล์เช่นstring1=very_complicated_valueและ a string2=another_long_and_complicated_value': โดยไม่ทราบรูปแบบภายในของไฟล์ของคุณฉันไม่สามารถแนะนำคำสั่งที่แม่นยำได้)


13

ฉันชอบcmpและประมวลผลคุณสมบัติการทดแทนของ bash:

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

เมื่อพูดในตำแหน่งที่ 2 ab จะเกิดขึ้นในครั้งแรก แต่ aq สำหรับวินาที ที่ตำแหน่ง 5 ความแตกต่างอื่นกำลังเกิดขึ้น เพียงแค่แทนที่สตริงเหล่านั้นด้วยตัวแปรเท่านี้ก็เสร็จแล้ว


สิ่งนี้ใช้ได้เฉพาะเมื่อสตริงมีความยาวเท่ากัน!
strpeter

11

สมมติว่าคุณมีสามสาย

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

ในการลบคำนำหน้า b จาก a

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

ในการลบคำต่อท้าย c ออกจาก a

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

2
ฉันเดาว่านี่เป็นวิธีการทุบตี มันทำงานได้ดี ไวยากรณ์นั้นยากที่จะเข้าใจ
Mikael Roos

@MikaelRoos เห็นด้วย อ่านง่ายกว่า (สำหรับฉันแล้ว) จะใช้ sed: echo "$a" | sed "s!^$b!!g" (ฉันสลับตัวคั่น sed มาตรฐาน / for! ในกรณีที่ตัวแปรที่จัดการกับพา ธ นอกจากนี้คุณสามารถใช้สตริงที่นี่แทน echo:. sed ... <<< $a)
ACK_stoverflow

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.