Làm thế nào để lệnh thay thế 'sed' này với nhiều dấu hiệu @ hoạt động?


8

Bất cứ ai có thể giải thích làm thế nào sedlệnh này hoạt động?

sed 's@+@ @g;s@%@\\x@g' | xargs -0 printf "%b"

3
Cách thông thường để làm điều này là sử dụng dấu gạch chéo, nhưng điều đó có thể trở nên cồng kềnh nếu bạn tìm kiếm và thay thế một cái gì đó bằng dấu gạch chéo. Đó không phải là trường hợp ở đây, vì vậy mặc dù nó hoàn toàn tốt nhưng nó gây nhầm lẫn cho những người duy trì trong tương lai như bạn.
Thorbjørn Ravn Andersen

2
Càng và dẫn họ học một cái gì đó mới về sedcách này! :)
món tráng miệng

Câu trả lời:


15

Trong sed, các lệnh thay thế thường được viết là s/pattern/replacement/options. Tuy nhiên, không cần thiết phải sử dụng /- bạn có thể sử dụng các ký tự khác nếu thuận tiện, vì vậy nó có thể s@pattern@replacement@optionshoặc s:foo:bar:g. s@+@ @ggiống như s/+/ /g- thay thế tất cả +bằng không gian. Tương tự s@%@\\x@gthay thế tất cả %bằng \x(một dấu gạch chéo ngược là một ký tự thoát trong sed, vì vậy bạn cần hai dấu gạch chéo ngược thực tế).

Một chuỗi như foo+%2Fbarsau đó sẽ trở thành foo \x2Fbar. printf "%b"sẽ mở rộng các chuỗi thoát dấu gạch chéo ngược như \x2F(ký tự ASCII có giá trị thập lục phân là 2F, /cuối cùng) để cung cấp cho bạn foo /bar.


2
Tóm lại, một bộ giải mã URL-> tên tệp.
Thorbjørn Ravn Andersen

10

Lệnh bạn đang yêu cầu giải mã +es và %chuỗi từ URL không chỉ là một sedlệnh, đó là một đường ống xử lý đầu vào sed, sau đó chuyển nó sang xargsxử lý tiếp. Đầu tiên chúng ta hãy nhìn vào sedlệnh:

sed 's@+@ @g;s@%@\\x@g'

Bạn có thể quen với việc nhìn thấy nó /hơn @là với dấu phân cách, điều có thể dễ dàng được thực hiện ở đây mà không có sự phức tạp vì /xuất hiện trong cả các mẫu tìm kiếm cũng như các văn bản thay thế. Lệnh này tương đương:

sed 's/+/ /g;s/%/\\x/g'

Giống như /, @là một nhân vật chấm câu hoàn toàn tốt cho sed.

Trên mỗi dòng đầu vào:

  1. s@+@ @g( s/+/ /g) thay thế ( s) lần xuất hiện của +với một khoảng trắng. Điều này ảnh hưởng đến tất cả +es trên một dòng ( g), không chỉ cái đầu tiên.

  2. ; kết thúc hành động ("lệnh") và cho phép bạn chỉ định một hành động khác trong cùng một "tập lệnh".

  3. s@%@\\x@g( s/%/\\x/g) thay thế ( s) lần xuất hiện của %với \x. Như trước đây, nó hoạt động trên tất cả thay vì chỉ đầu tiên của mỗi dòng ( g).

    Trong \\xnhững \\chỉ là một đại diện \\có một ý nghĩa đặc biệt để sed. Ý nghĩa đặc biệt của nó thực sự là nhân vật bạn sử dụng để lấy đi ý nghĩa đặc biệt của một nhân vật khác xuất hiện sau nó sẽ có ý nghĩa đặc biệt. Vì vậy, nó phải được thoát như \\.


Bây giờ hãy xem xargslệnh, mục đích của nó là chạy printf.

xargsxây dựng các dòng lệnh. Nếu bạn chạy , nơi có một hoặc nhiều từ, sẽ chạy với các đối số dòng lệnh bổ sung được đọc từ đầu vào của nó. Trong trường hợp này, đầu vào là đầu ra của , vì đường ống ( ). Thông thường diễn giải bất kỳ khoảng trắng nào trong đầu vào của nó có nghĩa là văn bản trước và sau nó tạo thành các đối số riêng biệt, nhưng tùy chọn làm cho nó phân tách các đối số tại các lần xuất hiện của ký tự null .xargs command...command...xargscommand...xargssed|xargs-0

Trong mục đích sử dụng lệnh của bạn, một ký tự null sẽ không xuất hiệnxargssẽ chạy printf %bchỉ với một đối số dòng lệnh bổ sung, đầu ra của sedlệnh. Do đó, mặc dù không tương đương nói chung, trong trường hợp này, toàn bộ đường ống có thể được viết như thế này bằng cách sử dụng thay thế lệnh thayxargs:

printf '%b\n' "$(sed 's/+/ /g;s/%/\\x/g')"

Đối với những gì printfđược dự định làm ở đây, như muru nói rằng trình %bxác định định dạng tiêu thụ và in một đối số (như %s) nhưng gây ra dấu gạch chéo ngược - của lệnh sắp xếp sedbên trái của đường ống được viết để tạo - được dịch vào các nhân vật mà họ đại diện .

Giả sử tôi chạy lệnh đó và chuyển http://foldoc.org/debugging%20by%20printflàm đầu vào. Tôi nhận được http://foldoc.org/debugging by printfnhư là đầu ra, bởi vì các %20chuỗi được dịch vào không gian.


3

Đó là vẻ đẹp của sed, nó áp dụng mô hình của mình cho bản thân ... Sau khi lệnh (chẳng hạn như shay trhoặc không có gì), nhân vật tiếp theo được coi là tách.

Bạn nên chọn một cách khôn ngoan để tránh sự can thiệp vào trình bao và chính lệnh đó, và giữ cho mọi thứ có thể đọc được, nhưng nó hoàn toàn hợp lệ để viết một cái gì đó kinh khủng như:

echo 'arrival' | sed srarbrg

... Và nhận được brrivblkết quả, đó là những gì bạn mong đợi. Bạn có thể vui vẻ làm cho nó thực sự khó hiểu, chẳng hạn như trong:

echo 'arrival' | sed s\fa\fb\fg   # \f is form feed, chr(12)

Việc sử dụng phổ biến là sử dụng dấu gạch chéo làm dấu phân cách, nhưng khi biểu thức của bạn chứa dấu phân cách, nó sẽ giúp bạn dễ dàng nắm bắt ý định đó là gì. Dấu phân cách của bạn có thể là bất cứ thứ gì trong phạm vi ASCII8 (các dấu phân cách đa dòng như £gây ra lỗi).

Chỉ cần nhớ mục tiêu là làm cho mọi thứ dễ dàng hơn, không khó hiểu hơn.


Chạy với ý tưởng khó hiểu, đây là một lệnh sed hợp lệ, mặc dù nó không làm được gì hữu ích:sed "snack is an apple or something" <<< "I sed your snack is an apple or something"
wjandrea

Đẹp! Vâng, bạn có thể sử dụng sedcác lệnh như trêu ghẹo não quá, làm thế nào là geeky?
Maraveoso
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.