ฉันมีผลลัพธ์จากVBoxManage list vms
ที่มีลักษณะเช่นนี้:
"arch" {de1a1db2-86c5-43e7-a8de-a0031835f7a7}
"arch2" {92d8513c-f13e-41b5-97e2-2a6b17d47b67}
ฉันต้องการที่จะคว้าชื่อarch
และarch2
และบันทึกไว้ในตัวแปร
ฉันมีผลลัพธ์จากVBoxManage list vms
ที่มีลักษณะเช่นนี้:
"arch" {de1a1db2-86c5-43e7-a8de-a0031835f7a7}
"arch2" {92d8513c-f13e-41b5-97e2-2a6b17d47b67}
ฉันต้องการที่จะคว้าชื่อarch
และarch2
และบันทึกไว้ในตัวแปร
คำตอบ:
นี่จะแยกเนื้อหาของ 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 ของคุณสามารถค้นหาสตริงย่อยใด ๆ ที่เริ่มต้นด้วยเครื่องหมายคำพูดคู่หรือลงท้ายด้วยเครื่องหมายคำพูดคู่และรายงานเพียงสตริงย่อย
/address/
ที่sed
ชอบsed '/^"\(arch[^"]*\)/s//\1/
คุณจะทำงานในบรรทัดที่มีสตริงนั้นเท่านั้น
sed
ควรจะทำจริงๆs/^"\([^"]*\)".*/\1/
ในกรณีที่มีเพียงสองเครื่องหมายคำพูดในบรรทัด
นั่นเป็นงานอีกอย่างสำหรับcut
:
VBoxManage list vms | cut -d \" -f2
cut
แบ่งแต่ละบรรทัดออกเป็นฟิลด์โดยใช้เครื่องหมายคำพูดเป็นตัวคั่นจากนั้นฟิลด์เอาท์พุต 2: ฟิลด์ 1 คือสตริงว่างก่อนอัญประกาศแรกฟิลด์ 2 เป็นสตริงที่ต้องการระหว่างเครื่องหมายคำพูดและฟิลด์ 3 เป็นส่วนที่เหลือของ เส้น
ด้วย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]}"
นี่อาจจะง่ายขึ้นเมื่อคุณใช้ตัวแปร
ใช้ทุบตีฉันจะเขียน:
while read vm value; do
case $vm in
'"arch"') arch=$value ;;
'"arch2"') arch2=$value ;;
esac
done < <( VBoxManage list vms )
echo $arch
echo $arch2
และหนึ่งผ่าน grep oneliner พร้อม--perl-regexp
ตัวเลือก
VBoxManage list vms | grep -oP '(?<=^\")[^"]*'
คำอธิบาย:
(?<=^\")[^"]*
-> Lookbehind ใช้ที่นี่ มันตรงกับตัวละครใด ๆ แต่ไม่"
เป็นศูนย์หรือมากกว่าครั้ง (เมื่อพบคำพูดสองครั้งก็หยุดการจับคู่) ซึ่งเป็นเพียงหลังเครื่องหมายคำพูดคู่ (เฉพาะบรรทัดที่เริ่มต้นด้วยคำพูดคู่)
อื่นผ่านสับน่าเกลียดsed
,
$ sed '/.*\"\(.*\)\".*/ s//\1/g' file
arch
arch2
เนื่องจาก regex มีโหมดโลภและไม่โลภหากคุณมีเป้าหมายหลายรายการในบรรทัดเดียวกันมันจะไม่แยกตามที่คุณต้องการ เส้น:
"tom" is a cat, and "jerry" is a mouse.
เป้าหมาย:
tom
jerry
คำสั่ง (โหมดโลภ):
grep -oP '".*"' name
คำสั่ง (โหมดที่ไม่ใช่โลภ):
grep -oP '".*?"' name
tr -d \"
เป็นอีกวิธีในการลบเครื่องหมายคำพูด (tr
โดยปกติจะแปลอักขระหนึ่งชุดเป็นอีกชุดหนึ่ง-d
ให้บอกให้ลบทิ้งแทน)