sed trên OSX chèn tại một dòng nhất định


24

Vì vậy, tôi đã sử dụng 'sed' trên linux trong một thời gian, nhưng đã gặp một chút khó khăn khi cố gắng sử dụng nó trên OSX vì 'POSIX sed' và 'GNU sed' có rất nhiều khác biệt. Hiện tại tôi đang vật lộn với cách chèn một dòng văn bản sau một số dòng nhất định. (trong trường hợp này, dòng 4)

Trên linux tôi sẽ làm một cái gì đó như thế này:

sed --in-place "4 a\  mode '0755'" file.txt

Vì vậy, trên OSX tôi đã thử điều này:

sed -i "" "4 a\ mode '0755'" file.txt

Tuy nhiên, điều này tiếp tục cho tôi một 'ký tự phụ sau \ ở cuối lệnh'. Có ý kiến ​​gì sai ở đây không? Tôi có mắc lỗi đánh máy không? Hay tôi không hiểu sự khác biệt giữa các phiên bản của sed?


2
Có thể xác nhận điều này để không hoạt động trên MacOS 10.6.8. Hoạt động tốt trên debian 6.0.3.
tink

Câu trả lời:


24

Nói đúng ra, đặc tả POSIXsed yêu cầu một dòng mới sau a\:

[1addr]a\
text

Viết văn bản vào đầu ra tiêu chuẩn như được mô tả trước đây.

Điều này làm cho văn bản một lớp lót một chút đau đớn, mà có lẽ là lý do sau mở rộng GNU đến a, iclệnh:

Là một phần mở rộng GNU, nếu giữa dòng avà dòng mới không phải là một khoảng trắng \, thì văn bản của dòng này, bắt đầu từ ký tự không phải khoảng trắng đầu tiên sau a, được lấy làm dòng đầu tiên của khối văn bản . (Điều này cho phép đơn giản hóa trong việc tạo kịch bản thêm một dòng.) Tiện ích mở rộng này cũng hoạt động với các lệnh ic.

Do đó, để có thể di động với sedcú pháp của bạn , bạn sẽ cần phải bao gồm một dòng mới sau phần a\nào đó. Cách dễ nhất là chỉ cần chèn một dòng mới được trích dẫn:

$ sed -e 'a\
> text'

(nơi $>là dấu nhắc vỏ). Nếu bạn thấy đau, bash[1] có $' 'cú pháp trích dẫn để chèn thoát kiểu C, vì vậy chỉ cần sử dụng

sed -e 'a\'$'\n''text'

[1] và mksh (r39b +) và một số vỏ bourne không bash (ví dụ: / bin / sh trong FreeBSD 9+)


Câu trả lời rất nhiều thông tin. Cảm ơn bạn đã gợi ý về cú pháp trích dẫn bash.
cjackson

14

Như được mô tả trong câu trả lời này , thật hữu ích khi sử dụng các lệnh sed như iasử dụng nhiều -e "..."mệnh đề. Mỗi mệnh đề này sẽ được hiểu là được phân tách bằng các dòng mới. Các lệnh iakhó sử dụng trong các tập lệnh sed nội tuyến (chúng được thiết kế để sử dụng trong tập tin tập lệnh sed đa dòng được gọi bằng cách sử dụng sed -f file ...). Có vẻ như bạn không thể sử dụng dòng mới ẩn được giới thiệu ở cuối một -emệnh đề để phân tách dòng a\và văn bản sẽ được thêm vào. Nhưng bạn có thể sử dụng nó để chấm dứt dòng văn bản sẽ được nối thêm.

Trong trường hợp cụ thể này, những gì bạn đang cố gắng thực tế có thể được thực hiện bằng một -e ...mệnh đề duy nhất . Bạn chỉ cần sử dụng alệnh chính xác. Theo tiêu chuẩn POSIX, acần phải được theo sau bởi a \, sau đó cần phải được theo sau bởi một dòng mới, sau đó phần còn lại của dòng tiếp theo sẽ được chèn vào (cho đến khi gặp dòng mới hoặc kết thúc -emệnh đề). Vì vậy, bạn có thể làm:

sed -i "" -e $'4 a\\\n'"mode '0755'" file.txt

2
Nếu bạn muốn sắp xếp những tính năng mà bạn đang dựa vào là Gnu-isms, trang này có thể giúp: wiki.alpinelinux.org/wiki/Regex . Tuy nhiên, nó chỉ giới hạn ở các tính năng regex; không phải các lệnh sed khác.
dubiousjim

5

GNU sed dường như được sử dụng phổ biến hơn nhiều so với POSIX sed, dựa trên các ví dụ / hướng dẫn mà tôi đã sử dụng.

Tôi thấy rằng việc cài đặt GNU sed trên bất kỳ máy OSX nào tôi sử dụng dễ dàng hơn nhiều. Nếu bạn quan tâm, cách tốt nhất để làm điều này là cài đặt nó thông qua Homebrew .

Bạn có thể chỉ $ brew install gnu-sedhoặc có được tất cả các tiện ích GNU phổ biến với $ brew install coreutils.

Sau đó, khi bạn gặp phải một vấn đề cú pháp với datehoặc một số chương trình khác, bạn chỉ có thể sử dụng phiên bản GNU. Cuối cùng, tôi quyết định sẽ luôn dễ dàng hơn khi luôn sử dụng các phiên bản GNU và đặt chúng sớm hơn các phiên bản hệ thống trong tôi PATH.


5

Perl không bị ảnh hưởng bởi các đặc điểm riêng của GNU so với non-GNU so với "idiosyncrasies". Bạn có thể làm:

perl -ni.old -e 'print;if ($.==4) {print "mode 0755\n"}' file

Các -n' option creates a loop that reads every line of the input file. Unlike its cousin-p (not used here) it doesn't automatically print every line read. The-i invokes in-place replacement. The argument to-i (viz. ".old") can be dropped or changed. It leaves a backup of the unmodified file. The -ebáo hiệu sự bắt đầu của kịch bản.

Số $.biểu thị số dòng, bắt đầu bằng dòng-1. Do đó, dòng lệnh đọc 'tệp' và khi số dòng bằng 4, nó sẽ in dòng đó theo sau bất cứ thứ gì bạn muốn tiêm.

Tôi sẽ nhanh chóng thêm rằng Perl nợ gốc của nó sed, AWK và C, vì vậy cú pháp cho các thay thế đơn giản, v.v. không phải là một đường cong học tập rất dốc.


Câu trả lời tốt đẹp! Nhưng bạn có thể đơn giản hóa nó một chút. Hãy thử điều này : perl -wlpi.old -e 'print "mode 0755" if $. == 5' file.txt. Công -ptắc hoạt động tốt ở đây (vì chúng tôi muốn in mọi dòng); chúng ta chỉ cần thay đổi logic từ "in sau dòng 4" sang "in trước dòng 5". Và công -ltắc làm cho nó sao cho "\ n" được in tự động với mọi thứ print, vì vậy bạn không phải tự in.
JL
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.