2012-04-02 39 views
9

echo ddayaynightday | sed 's/day//g'Sed thay đệ quy

Nó kết thúc lên daynight

Liệu có cách nào để làm cho nó thay thế cho đến khi không phù hợp hơn?

+0

Lặp lại cho đến khi chiều dài của nó sẽ ngừng thay đổi. Không biết, làm thế nào để làm điều đó trong vỏ. – kirilloid

Trả lời

17

hình thức ưa thích của tôi, đối với trường hợp này:

echo ddayaynightday | sed -e ':loop' -e 's/day//g' -e 't loop' 

Đây là giống như mọi người khác, ngoại trừ việc nó sử dụng lệnh nhiều -e để làm ba dòng và sử dụng cấu trúc t — có nghĩa là "nhánh nếu bạn đã thay thế thành công" —để lặp lại.

+1

Tốt để biết cách nhập nhiều dòng tập lệnh trên dòng lệnh trong trường hợp ";" sẽ không hoạt động. Tôi cũng thích câu trả lời của bạn hơn vì bước nhảy có điều kiện 't' rõ ràng hơn đối với tôi, trái ngược với một mẫu phù hợp với nhảy vô điều kiện. –

+0

cảm ơn :) tôi nghĩ rằng điều này có vẻ tốt, không chắc chắn nếu có một cách tốt hơn bằng cách sử dụng một số cũ thường xuyên mở rộng .. – w00d

3

Cờ g cố tình không khớp lại với phần được thay thế của chuỗi. Những gì bạn cần làm là hơi khác một chút. Hãy thử điều này:

echo ddayaynightday | sed $':begin\n/day/{ s///; bbegin\n}' 

Do yêu cầu của BSD Sed, nên sử dụng dòng mới được nhúng. Nếu bạn đang sử dụng GNU Sed bạn có thể nhận được ngay với

sed ':begin;/day/{ s///; bbegin }' 
+0

Trong vỏ sành điệu, bạn cũng có thể chèn một dòng mới vào bên trong một chuỗi được trích dẫn. Mặt khác, tôi tìm chuỗi '$ '... với escape ...'' xây dựng đẹp hơn cho các đoạn mã ngắn như thế này. Đối với các tập lệnh thực sự dài, sử dụng '-f file' có lẽ tốt hơn. Trong trường hợp cụ thể này, nhiều lệnh '-e' cũng hoạt động. – torek

+0

@torek: Điểm tốt về nhiều lệnh '-e'. Cá nhân tôi ghét nhúng dòng mới vào chuỗi được trích dẫn. Nó thường khó đọc và làm cho nó khó khăn hơn nhiều để chia sẻ lệnh với người khác (vì các lệnh thường được dự kiến ​​là trên một dòng). –

+0

cảm ơn, thứ 2 của bạn không hoạt động trên osx của tôi, nó chỉ in ra đầu vào – w00d

1

Các công trình sau đây:

$ echo ddayaynightday | sed ':loop;/day/{s///g;b loop}' 
night 

Tùy thuộc vào hệ thống của bạn, ; có thể không hoạt động với các lệnh riêng biệt, vì vậy bạn có thể sử dụng sau đây thay vì:

echo ddayaynightday | sed -e ':loop' -e '/day/{s///g 
               b loop}' 

Giải thích:

:loop  # Create the label 'loop' 
/day/{  # if the pattern space matches 'day' 
    s///g  # remove all occurrence of 'day' from the pattern space 
    b loop # go back to the label 'loop' 
} 

Nếu phần b loop của lệnh không được thực hiện, nội dung hiện tại của không gian mẫu sẽ được in và dòng tiếp theo sẽ được đọc.

+0

Gọn gàng, dude!321 – Almo

+0

Điều này không phù hợp với tôi. Nó đưa ra một lỗi: 'sed: 1:": loop;/day/{s/day // g; b ... ": vòng lặp không sử dụng nhãn ';/day/{s/day // g; b loop} '' – Graham

+0

Dấu chấm phẩy chỉ hoạt động trong một số phiên bản của sed. – torek

0

Ok, ở đây chúng là: whilestrlen trong bash. Sử dụng chúng ta có thể thực hiện ý tưởng của tôi:

Repeat until its length will stop changing.

Có không cách để thiết lập cờ cũng không cách nào để viết regex như vậy, để "thay thế cho đến khi không phù hợp hơn".

5

Điều này có thể làm việc cho bạn:

echo ddayaynightday | sed ':a;s/day//g;ta' 
night 
+0

không hoạt động trên osx – w00d

+0

Có vẻ như bạn cần nhiều công tắc '-e' – potong

+0

Nó * hoạt động trên OSX 10.6.8 – MASL

2

với bash:

str=ddayaynightday 
while true; do tmp=${str//day/}; [[ $tmp = $str ]] && break; str=$tmp; done 
echo $str