Sử dụng sed nhận chuỗi con giữa hai dấu ngoặc kép


14

Tôi có một tập tin

xyz... rsync: "/home/path/to/file": Permission denied (13) rsync:
"/home/path/to/file1": Permission denied (13) rsync:
"/home/path/to/file2": Permission denied (13) rsync:
"/home/path/to/file3": Permission denied (13)

Bây giờ tôi chỉ muốn trích xuất các đường dẫn tệp và lưu trữ nó vào một tệp khác. Tập tin đầu ra giống như:

/home/path/to/file 
/home/path/to/file1 
/home/path/to/file2
/home/path/to/file3

Sử dụng sed hoặc awk làm thế nào tôi có thể làm điều này?

Tôi đã thử sed -n '/"/,/"/p' myfilenhưng nó không hoạt động.


3
Để những người bỏ phiếu đóng cửa - Làm thế nào điều này có thể lạc đề? Đó là về lập trình shell !! Đó là LẬP TRÌNH TRÊN TOPIC cho Stack Overflow!
Jonathan Leffler

2
Chào mừng bạn đến với Stack Overflow. Như bạn có thể thấy, đôi khi chúng tôi gặp vấn đề với những người bị ngứa ngón tay kích hoạt đóng những câu hỏi hoàn toàn tốt (chẳng hạn như câu hỏi này) với lý do xấu để đóng cửa. Nó không xảy ra thường xuyên (hoặc, tôi không gặp vấn đề kịp thời thường xuyên), nhưng nó đã xảy ra. Đừng quên đọc FAQ trước khi quá lâu.
Jonathan Leffler

Câu trả lời:


17

Bạn có thể chuyển stderr của lệnh rsync thành tập lệnh awk:

awk -F '"' '{print $2}' 

Hoặc theo lệnh cắt như thế này:

cut -d'"' -f2

2
Hoặc, ngắn hơn:cut -d\" -f2

@AndersJohansson: Cảm ơn tôi đã thêm lệnh cắt của bạn để trả lời.
anubhava

Tôi nghĩ rằng điều này sẽ không hoạt động .. như bạn có thể thấy số trường của đường dẫn tệp không cố định $ 2 hoặc f2 .. Cảm ơn!

Trên thực tế rsync sẽ luôn luôn viết filepath trước giữa ""trên stderr.
anubhava

1
@ Jam88: Trên thực tế, nó sẽ hoạt động vì cách anubbhava đã viết nó. Dấu phân cách trường được đặt thành dấu ngoặc kép. Điều đó có nghĩa là tất cả mọi thứ cho đến trích dẫn kép đầu tiên (có thể là một chuỗi rỗng) là $1; tất cả mọi thứ giữa dấu ngoặc kép thứ nhất và thứ hai là $2; và mọi thứ sau trích dẫn kép thứ hai là trong $3( $4, ...). Tên tệp là (rõ ràng) luôn nằm giữa hai dấu ngoặc kép đầu tiên, vì vậy giải pháp này sẽ hoạt động (và đã làm khi tôi kiểm tra nó).
Jonathan Leffler

6

Sử dụng sed:

sed 's/^[^"]*"\([^"]*\)".*/\1/'

Điều đó tìm kiếm: đầu dòng, một loạt các trích dẫn, một trích dẫn kép, ghi lại một loạt các trích dẫn, một trích dẫn kép và bất cứ điều gì khác trên dòng, và thay thế nó bằng các tài liệu bị bắt.

$ sed 's/^[^"]*"\([^"]*\)".*/\1/' <<'EOF'
> xyz... rsync: "/home/path/to/file": Permission denied (13) rsync:
> "/home/path/to/file1": Permission denied (13) rsync:
> "/home/path/to/file2": Permission denied (13) rsync:
> "/home/path/to/file3": Permission denied (13)
> EOF
/home/path/to/file
/home/path/to/file1
/home/path/to/file2
/home/path/to/file3
$

Thử nghiệm trên RHEL 5 Linux với GNU sed, nhưng chỉ sử dụng các tính năng có thể hoạt động trong phiên bản UNIX ™ phiên bản thứ 7 của sed.

Ngẫu nhiên, một cách đơn giản hơn để làm điều đó là với hai lệnh thay thế; thay đổi mọi thứ lên đến và bao gồm cả trích dẫn kép đầu tiên thành một chuỗi trống (đó là một chuỗi gồm 0 hoặc nhiều hơn các trích dẫn không theo sau là một trích dẫn kép); thay đổi mọi thứ sau những gì bây giờ là trích dẫn kép đầu tiên thành không có gì:

sed 's/^[^"]*"//; s/".*//'

Ngẫu nhiên, lệnh bạn đã thử (`sed -n '/" /, / "/ p') in từ một dòng chứa một trích dẫn kép sang dòng tiếp theo chứa một trích dẫn kép, mà không chỉnh sửa các dòng nào cả. Đó là lý do tại sao nó dường như không làm việc cho bạn - nó đã làm những gì bạn yêu cầu, nhưng những gì bạn yêu cầu nó làm không phải là những gì bạn định yêu cầu nó làm.

Hiệu quả-khôn ngoan, không có khả năng là một sự khác biệt có thể đo lường được trong hiệu suất. Về mặt dễ bảo trì, tôi nghi ngờ cái sau ít đánh thuế vào các tế bào não.


1

Nếu phiên bản grephỗ trợ của bạn Perl-regapi:

grep -oP '(?<=")/home/.*?(?=")' file >> anotherfile

Các kết quả:

/home/path/to/file
/home/path/to/file1
/home/path/to/file2
/home/path/to/file3

Bạn cũng có thể làm cho điều này bớt nghiêm ngặt hơn, để phù hợp với bất cứ điều gì giữa các đôi nếu bạn muốn:

grep -oP '(?<=")[^"]*' file >> anotherfile

Bạn có cần phải làm cho người .*không tham lam .*?chỉ trong trường hợp có thêm một trích dẫn kép sau dòng này không? Hoặc sử dụng [^"]*thay .*thế?
Jonathan Leffler

-1

Sử dụng toán tử >> để lưu bất kỳ đầu ra nào vào một tệp.

Giống

grep -r "pattern" * >> file.txt

Vì vậy, chỉ cần thay đổi điều đó cho kịch bản cụ thể của bạn bằng cách sử dụng sed bằng cách nối thêm

>> filename

ra lệnh


Việc grep -rtìm kiếm đệ quy thông qua bất kỳ thư mục nào được liệt kê trong các đối số ( *). Không rõ bạn đang nghĩ đến mô hình nào, nhưng grepsẽ chọn toàn bộ dòng. Mục đích của bài tập là thu thập thông tin từ một phần của một dòng. Nếu bạn đang sử dụng GNU grep, có nhiều cách để làm điều đó ( -o); đây là những tiêu chuẩn không (trừ trường hợp GNU định nghĩa một tiêu chuẩn thực tế). Tương tự với việc sử dụng các biểu thức chính quy PCRE; đó là những phần mở rộng GNU khác. Chúng sẽ ổn nếu bạn có GNU grepvà không có kế hoạch hoạt động trên các nền tảng mà GNU grepkhông có sẵn theo mặc định.
Jonathan Leffler

Xin lỗi tôi đã bỏ lỡ điều đó, tôi nghĩ rằng anh ấy muốn biết nói chung phải làm gì để đưa đầu ra vào một tệp và grep chỉ là một ví dụ.
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.