Bagaimana cara mengekstrak konten string yang dikutip dari output sebuah perintah?

26

Saya memiliki output VBoxManage list vmsyang terlihat seperti ini:

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

Saya perlu untuk mengambil nama-nama archdan arch2dan menyimpannya ke dalam variabel.

Harrys Kavan
sumber

Jawaban:

34

Menggunakan grep + sed

Ini akan mem-parsing isi dari 2 string:

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

Di atas mencari string yang cocok dengan pola ".*". Itu akan cocok dengan apa pun yang terjadi dalam tanda kutip ganda. Jadi grepakan mengembalikan jenis nilai ini:

"arch"
"arch2"

Pipa untuk sedakan menghapus setiap tanda kutip ganda dari string ini memberikan Anda string yang Anda cari. Notasi sed 's/"//g'ini menginstruksikan seduntuk melakukan pencarian dan mengganti semua kemunculan tanda kutip ganda, menggantikannya dengan apa pun s/"//g,. Perintahnya s/find/replace/gadalah apa yang terjadi di sana, dan trailing gto search menyuruhnya melakukannya secara global pada seluruh string yang diberikan.

Hanya menggunakan sed

Anda juga dapat menggunakan seduntuk memangkas kuotasi awal, menyimpan apa yang ada di antara keduanya, dan memangkas kuotasi yang tersisa + semua yang ada setelahnya:

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

Metode lainnya

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

Perintah trdapat digunakan untuk menghapus karakter. Dalam hal ini menghapus tanda kutip ganda.

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

Dengan menggunakan grepfitur PCRE, Anda dapat mencari substring yang dimulai dengan penawaran ganda atau diakhiri dengan penawaran ganda dan melaporkan hanya substring tersebut.

slm
sumber
1
tr -d \"adalah cara lain untuk menghapus tanda kutip. ( trbiasanya menerjemahkan satu set karakter ke yang lain; -d
memintanya
1
slm - jika Anda menambah /address/untuk sedseperti sed '/^"\(arch[^"]*\)/s//\1/Anda hanya akan beroperasi pada baris yang mengandung string.
mikeserv
1
@ mikeserv - benar, tidak yakin seberapa konsisten lengkungan akan menjadi outputnya. Tetapi jika ya, maka itu akan berhasil juga.
slm
1
poin bagus slm. Tidak ada indikasi yang konsisten. Maaf.
mikeserv
2
Namun saya baru menyadari bahwa Anda sedbenar-benar harus melakukan s/^"\([^"]*\)".*/\1/kalau-kalau ada hanya dua tanda kutip ganda di telepon.
mikeserv
19

Itu pekerjaan lain untuk cut:

VBoxManage list vms | cut -d \" -f2
Stéphane Chazelas
sumber
3
Sangat rapi! Cara kerjanya: cutmembagi setiap baris menjadi bidang-bidang menggunakan tanda kutip sebagai pembatas, kemudian menghasilkan bidang 2: bidang 1 adalah string kosong sebelum kutipan pertama, bidang 2 adalah string yang dicari antara tanda kutip, dan bidang 3 adalah sisa dari baris.
deltab
7

Dengan sedAnda dapat melakukan:

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

Penjelasan:

  • s/.../.../ - cocok dan ganti
  • ^- cocok pada awal baris
  • \(...\) - ini adalah referensi belakang, kita dapat merujuk pada apa yang cocok di sini nanti dengan \1
  • [^"]*- cocok dengan urutan apa pun yang tidak mengandung "(yaitu hingga yang berikutnya ")
  • .* - cocok dengan sisa baris
  • \1 - ganti dengan referensi belakang

Atau dengan awk:

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

Perhatikan bahwa dalam shell modern Anda juga dapat menggunakan array alih-alih variabel normal. Di dalam bashkamu dapat melakukan:

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

Ini mungkin lebih mudah ketika Anda datang untuk menggunakan variabel.

Graeme
sumber
Tolong, bisakah kau putuskan perintah sed itu untukku?
Harrys Kavan
5

Menggunakan bash, saya akan menulis:

while read vm value; do
    case $vm in
        '"arch"') arch=$value ;;
        '"arch2"') arch2=$value ;;
    esac
done < <( VBoxManage list vms )
echo $arch
echo $arch2
glenn jackman
sumber
5

Dan satu melalui grep oneliner dengan --perl-regexpopsi,

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

Penjelasan:

(?<=^\")[^"]*-> Pandangan di belakang digunakan di sini. Ini cocok dengan karakter apa pun tetapi tidak dari "nol atau lebih kali (setelah itu menemukan tanda kutip ganda, itu berhenti cocok) yang hanya setelah tanda kutip ganda (hanya garis yang dimulai dengan tanda kutip ganda).

Peretasan lain yang jelek sed,

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

karena regex memiliki mode serakah dan non-serakah, jika Anda memiliki beberapa target pada baris yang sama, regex tidak akan mengekstraksi seperti yang Anda inginkan. Baris:

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

Target:

tom
jerry

Perintah (mode serakah):

grep -oP '".*"' name

Perintah (mode non-serakah):

grep -oP '".*?"' name
Tiina
sumber