Làm cách nào để trích xuất nội dung của các chuỗi được trích dẫn từ đầu ra của lệnh?


26

Tôi có đầu ra từ VBoxManage list vmsđó trông như thế này:

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

Tôi cần phải lấy tên archarch2và lưu chúng vào một biến.

Câu trả lời:


34

Sử dụng grep + sed

Điều này sẽ phân tích nội dung của 2 chuỗi đó:

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

Ở trên tìm kiếm một chuỗi phù hợp với mô hình ".*". Điều đó sẽ phù hợp với bất cứ điều gì xảy ra trong dấu ngoặc kép. Vì vậy, grepsẽ trả về các loại giá trị:

"arch"
"arch2"

Các đường ống sedsẽ loại bỏ bất kỳ dấu ngoặc kép nào từ các chuỗi này cung cấp cho các chuỗi bạn đang tìm kiếm. Ký hiệu sed 's/"//g'này đang hướng dẫn sedthực hiện tìm kiếm và thay thế trên tất cả các lần xuất hiện của dấu ngoặc kép, thay thế chúng bằng không có gì , s/"//g. Lệnh s/find/replace/glà những gì đang diễn ra ở đó, và dấu vết gđể tìm kiếm bảo nó thực hiện nó trên toàn cầu trên toàn bộ chuỗi mà nó đưa ra.

Chỉ sử dụng sed

Bạn cũng có thể sử dụng sedđể cắt bỏ trích dẫn kép bắt đầu, giữ những gì ở giữa chúng và cắt bỏ phần trích dẫn còn lại + mọi thứ ở đó sau:

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

Các phương pháp khác

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

Lệnh trcó thể được sử dụng để xóa các ký tự. Trong trường hợp này, nó sẽ xóa dấu ngoặc kép.

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

Sử dụng greptính năng PCRE của bạn, bạn có thể tìm kiếm bất kỳ chuỗi con nào bắt đầu bằng dấu ngoặc kép hoặc kết thúc bằng dấu ngoặc kép và chỉ báo cáo chuỗi con.


1
tr -d \"là một cách khác để xóa dấu ngoặc kép. ( trthông thường sẽ dịch một bộ ký tự thành một ký tự khác; -dbảo nó chỉ xóa chúng đi.)
deltab

1
SLM - nếu bạn thêm một /address/đến sednhư sed '/^"\(arch[^"]*\)/s//\1/bạn sẽ chỉ hoạt động trên các dòng có chứa chuỗi đó.
mikeerv

1
@mikeerv - đúng, không chắc chắn rằng vòm sẽ ổn định như thế nào trong sản phẩm của anh ấy. Nhưng nếu có, thì nó cũng sẽ hoạt động.
slm

1
điểm tốt slm. Không có dấu hiệu nào phù hợp. Lấy làm tiếc.
mikeerv

2
Tôi chỉ nhận ra rằng bạn sedthực sự nên làm s/^"\([^"]*\)".*/\1/trong trường hợp không chỉ có hai dấu ngoặc kép trên dòng.
mikeerv

19

Đó là một công việc khác cho cut:

VBoxManage list vms | cut -d \" -f2

3
Rât gọn gang! Cách thức hoạt động: cutchia từng dòng thành các trường bằng cách sử dụng dấu ngoặc kép làm dấu phân cách, sau đó xuất trường 2: trường 1 là chuỗi trống trước trích dẫn đầu tiên, trường 2 là chuỗi mong muốn giữa các dấu ngoặc kép và trường 3 là phần còn lại của hàng.
deltab

7

Với sedbạn có thể làm:

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

Giải trình:

  • s/.../.../ - phù hợp và thay thế
  • ^- trận đấu ở đầu dòng
  • \(...\) - đây là một tài liệu tham khảo trở lại, chúng ta có thể tham khảo những gì phù hợp ở đây sau với \1
  • [^"]*- khớp với bất kỳ chuỗi nào không chứa "(tức là đến chuỗi tiếp theo ")
  • .* - phù hợp với phần còn lại của dòng
  • \1 - thay thế bằng tham chiếu trở lại

Hoặc với awk:

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

Lưu ý rằng trong shell hiện đại, bạn cũng có thể sử dụng một mảng thay vì một biến thông thường. Trong bashbạn có thể làm:

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

Điều này có thể dễ dàng hơn khi bạn sử dụng biến.


Bạn có thể phá vỡ lệnh sed đó cho tôi không?
Harrys Kavan

5

Sử dụng bash, tôi sẽ viết:

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

5

Và một thông qua grep oneliner với --perl-regexptùy chọn,

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

Giải trình:

(?<=^\")[^"]*-> Một cái nhìn được sử dụng ở đây. Nó phù hợp với bất kỳ nhân vật nào nhưng không phải của" bằng 0 hoặc nhiều lần (một khi tìm thấy dấu ngoặc kép, nó dừng khớp) chỉ sau dấu ngoặc kép (chỉ dòng bắt đầu bằng dấu ngoặc kép).

Một hack xấu xí khác sed,

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

0

vì regex có chế độ tham lam và không tham lam, nếu bạn có nhiều mục tiêu trên cùng một dòng, nó sẽ không trích xuất như bạn muốn. Hàng:

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

Mục tiêu:

tom
jerry

Lệnh (chế độ tham lam):

grep -oP '".*"' name

Lệnh (chế độ không tham lam):

grep -oP '".*?"' name
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.