ฉันจะแยกเนื้อหาของสตริงที่ยกมาจากผลลัพธ์ของคำสั่งได้อย่างไร


26

ฉันมีผลลัพธ์จากVBoxManage list vmsที่มีลักษณะเช่นนี้:

"arch" {de1a1db2-86c5-43e7-a8de-a0031835f7a7}   
"arch2" {92d8513c-f13e-41b5-97e2-2a6b17d47b67}  

ฉันต้องการที่จะคว้าชื่อarchและarch2และบันทึกไว้ในตัวแปร

คำตอบ:


34

ใช้ grep + sed

นี่จะแยกเนื้อหาของ 2 สายเหล่านี้:

$ grep -o '".*"' somefile | sed 's/"//g'
arch
arch2

".*"ลักษณะดังกล่าวข้างต้นเป็นข้อความที่ตรงกับรูปแบบ ที่จะตรงกับสิ่งที่เกิดขึ้นภายในเครื่องหมายคำพูดคู่ ดังนั้นgrepจะส่งคืนค่าประเภทเหล่านี้:

"arch"
"arch2"

ไปป์ที่sedจะตัดเครื่องหมายคำพูดคู่ใด ๆ จากสตริงเหล่านี้ให้สตริงที่คุณต้องการ สัญกรณ์sed 's/"//g'จะสอนจะค้นหาและแทนที่ในเหตุการณ์ที่เกิดขึ้นทั้งหมดของคำพูดคู่แทนพวกเขาด้วยอะไรsed s/"//gคำสั่งs/find/replace/gคือสิ่งที่เกิดขึ้นที่นั่นและการติดตามgเพื่อค้นหาบอกให้ทำแบบโกลบอลบนสตริงทั้งหมดที่ได้รับ

ใช้เพียงแค่ใจเย็น ๆ

คุณยังสามารถใช้sedเพื่อตัดเครื่องหมายอัญประกาศเริ่มต้นเก็บสิ่งที่อยู่ระหว่างพวกเขาและตัดเครื่องหมายอัญประกาศที่เหลือ + ทุกอย่างที่มีหลังจาก:

$ sed 's/^"\(.*\)".*/\1/' a
arch
arch2

วิธีอื่น ๆ

$ grep -o '".*"' somefile | tr -d '"'
arch
arch2

trสามารถใช้คำสั่งเพื่อลบอักขระได้ ในกรณีนี้มันเป็นการลบเครื่องหมายคำพูดคู่

$ grep -oP '(?<=").*(?=")' somefile
arch
arch2

การใช้grepคุณสมบัติ PCRE ของคุณสามารถค้นหาสตริงย่อยใด ๆ ที่เริ่มต้นด้วยเครื่องหมายคำพูดคู่หรือลงท้ายด้วยเครื่องหมายคำพูดคู่และรายงานเพียงสตริงย่อย


1
tr -d \"เป็นอีกวิธีในการลบเครื่องหมายคำพูด ( trโดยปกติจะแปลอักขระหนึ่งชุดเป็นอีกชุดหนึ่ง-dให้บอกให้ลบทิ้งแทน)
deltab

1
slm - หากคุณเพิ่มสิ่ง/address/ที่sedชอบsed '/^"\(arch[^"]*\)/s//\1/คุณจะทำงานในบรรทัดที่มีสตริงนั้นเท่านั้น
mikeserv

1
@ mikeserv - จริงไม่แน่ใจว่าส่วนโค้งที่สอดคล้องกันจะเป็นอย่างไรในผลลัพธ์ของเขา แต่ถ้าเป็นเช่นนั้นก็จะใช้ได้เช่นกัน
slm

1
จุดดี slm ไม่มีข้อบ่งชี้ว่าจะสอดคล้องกัน ขอโทษ
mikeserv

2
ฉันเพิ่งรู้ว่าคุณsedควรจะทำจริงๆs/^"\([^"]*\)".*/\1/ในกรณีที่มีเพียงสองเครื่องหมายคำพูดในบรรทัด
mikeserv

19

นั่นเป็นงานอีกอย่างสำหรับcut:

VBoxManage list vms | cut -d \" -f2

3
เรียบร้อยมาก! มันทำงานอย่างไร: cutแบ่งแต่ละบรรทัดออกเป็นฟิลด์โดยใช้เครื่องหมายคำพูดเป็นตัวคั่นจากนั้นฟิลด์เอาท์พุต 2: ฟิลด์ 1 คือสตริงว่างก่อนอัญประกาศแรกฟิลด์ 2 เป็นสตริงที่ต้องการระหว่างเครื่องหมายคำพูดและฟิลด์ 3 เป็นส่วนที่เหลือของ เส้น
deltab

7

ด้วยsedคุณสามารถทำ:

var=$(VBoxManage list vms | sed 's/^"\([^"]*\).*/\1/')

คำอธิบาย:

  • s/.../.../ - จับคู่และแทนที่
  • ^- การแข่งขันที่จุดเริ่มต้นของบรรทัด
  • \(...\) - นี่คือการอ้างอิงย้อนกลับเราสามารถอ้างถึงสิ่งที่ตรงกับที่นี่ในภายหลังด้วย \1
  • [^"]*- จับคู่ลำดับใด ๆ ที่ไม่มี"(เช่นจนถึงลำดับถัดไป")
  • .* - จับคู่ส่วนที่เหลือของบรรทัด
  • \1 - แทนที่ด้วยการอ้างอิงด้านหลัง

หรือด้วยawk:

var=$(VBoxManage list vms | awk -F\" '{ print $2 }')

โปรดทราบว่าในเชลล์ที่ทันสมัยคุณสามารถใช้อาร์เรย์แทนตัวแปรปกติได้ ในbashสิ่งที่คุณสามารถทำได้:

IFS=$'\n'; set -f
array=( $(VBoxManage list vms | awk -F\" '{ print $2 }') )
echo "array[0] = ${array[0]}"
echo "array[1] = ${array[1]}"

นี่อาจจะง่ายขึ้นเมื่อคุณใช้ตัวแปร


คุณจะทำลายคำสั่ง sed ที่ขึ้นสำหรับฉันได้ไหม
Harrys Kavan


5

และหนึ่งผ่าน grep oneliner พร้อม--perl-regexpตัวเลือก

VBoxManage list vms | grep -oP '(?<=^\")[^"]*'

คำอธิบาย:

(?<=^\")[^"]*-> Lookbehind ใช้ที่นี่ มันตรงกับตัวละครใด ๆ แต่ไม่"เป็นศูนย์หรือมากกว่าครั้ง (เมื่อพบคำพูดสองครั้งก็หยุดการจับคู่) ซึ่งเป็นเพียงหลังเครื่องหมายคำพูดคู่ (เฉพาะบรรทัดที่เริ่มต้นด้วยคำพูดคู่)

อื่นผ่านสับน่าเกลียดsed,

$ sed '/.*\"\(.*\)\".*/ s//\1/g' file
arch
arch2

0

เนื่องจาก regex มีโหมดโลภและไม่โลภหากคุณมีเป้าหมายหลายรายการในบรรทัดเดียวกันมันจะไม่แยกตามที่คุณต้องการ เส้น:

"tom" is a cat, and "jerry" is a mouse. 

เป้าหมาย:

tom
jerry

คำสั่ง (โหมดโลภ):

grep -oP '".*"' name

คำสั่ง (โหมดที่ไม่ใช่โลภ):

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