Dòng mới về sed trên Mac OS X


44

Tôi thấy rằng \nnó không hoạt động trong sed trong Mac OS X. Cụ thể, nói rằng tôi muốn chia các từ được phân tách bằng một khoảng trắng thành các dòng:

# input
foo bar

Tôi sử dụng,

echo "foo bar" | sed 's/ /\n/'

Nhưng kết quả là ngu ngốc, \nkhông thoát được!

foonbar

Sau khi tôi tham khảo ý kiến ​​trên google, tôi đã tìm thấy một cách giải quyết :

echo 'foo bar' | sed -e 's/ /\'$'\n/g'

Sau khi đọc bài báo, tôi vẫn không thể hiểu ý \'$'\n/g'nghĩa của nó. Ai đó có thể giải thích cho tôi, hoặc nếu có cách nào khác để làm điều đó? Cảm ơn!


điều này có lẽ cũng sẽ hoạt động:echo "foo bar" | tr ' ' '\n'
glenn jackman

3
Cảm ơn vì lời khuyên. Nhưng hiện tại tôi chỉ sử dụng trường hợp trên làm ví dụ, tôi cần biết cách thoát a \n.
Ivan ZG Xiao

Câu trả lời:


27

Bạn có thể brew install gnu-sedvà thay thế các cuộc gọi đến sedvới gsed.

Nếu bạn không muốn thêm "g" vào sed, bạn có thể brew install gnu-sed --with-default-namesvà chỉ cần gọi sed.

(Chỉnh sửa: cập nhật cờ bia, đầu mũ thành Clément.)


Sử dụng cùng một phần mềm trên tất cả các nền tảng là cách dễ dàng hơn (cuối cùng đối với tôi) so với việc xử lý mọi đặc thù của phiên bản Mac. Hãy coi chừng, tùy chọn là bây giờ --with-default-nameskhông --default-names . Tuy nhiên, tùy chọn này không hoạt động trong quá trình cài đặt của tôi, vì vậy tôi phải đặt nó alias gsed=sedvào ~/.profileđể làm cho nó hoạt động.
Clément

4
Đây là một cách giải quyết xấu xí. Nó không giải thích tại sao sedtrên OS X hành xử theo cách của nó và đưa ra giả định không chính xác gnu-sedthì đúng hơn. Đừng là người nghiện GNU và tuân thủ các tiêu chuẩn POSIX để tránh các vấn đề về lâu dài.
octosquidopus 8/10/2015

Đó là cách Apple nên làm cho hệ điều hành của nó hoạt động theo mặc định. Tại sao sử dụng tên của một chương trình và sau đó làm cho nó hoạt động khác nhau? Tôi lãng phí một giờ vì điều này ...
rascio

@rascio - vì OS X giống BSD và Linux giống Linux.
iAdjunc

@rascio Tôi nghĩ bạn sẽ thấy GNU sed là người mới; BSD sed có từ năm 1979 (xem en.wikipedia.org/wiki/Version_7_Unix ).
Duncan Bayne

24

Đây cũng sẽ làm việc:

echo 'foo bar' | sed 's/ /\
/g'

echo 'foo bar' | sed $'s/ /\\\n/g'

lf=$'\n'; echo 'foo bar' | sed "s/ /\\$lf/g"

Sed X của OS X không diễn giải \ntheo mẫu thay thế, nhưng bạn có thể sử dụng nguồn cấp dữ liệu bằng chữ đứng trước ký tự tiếp tục dòng. Shell thay thế $'\n'bằng một linefeed theo nghĩa đen trước khi lệnh sed được chạy.


4
Tại sao không sed $'s/ /\\\n/g'làm việc, nhưng không sed $'s/\\\n/ /g'?
Alec Jacobson

1
@alec Bạn không thể sử dụng sedngay cả trong linux / unix để xóa dòng mới vì nó được phân tách / phân tách ở mỗi dòng mới. Nếu bạn chạy cái này trong linux / unix, nó sẽ không làm gì cả:echo -e 'foo\nbar' | sed 's/\n//'
wvducky

10

Cách giải quyết bạn tìm thấy vượt qua một chuỗi đối số duy nhất sed -e.

Đối số đó kết thúc là một chuỗi trong s/ / /gđịnh dạng sed quen thuộc .

Chuỗi đó được tạo thành hai phần, lần lượt từng phần.

Phần đầu tiên được trích dẫn trong '...'hình thức.

Phần thứ hai được trích dẫn trong $'...'hình thức.

Phần này 's/ /\'có các trích dẫn đơn bị loại bỏ, nhưng nếu không thì chuyển qua sed giống như trên dòng lệnh. Đó là, dấu gạch chéo ngược không được ăn bởi bash, nó được truyền cho sed.

Phần $'\n/g'được ký hiệu đô la và dấu ngoặc đơn bị loại bỏ và phần \nđược chuyển đổi thành ký tự dòng mới.

Tất cả cùng nhau, cuộc tranh cãi trở thành

s / / \ newline/ g

[Đó là niềm vui. Mất một lúc để mở khóa. +1 cho một câu hỏi thú vị.]


7

Biểu thức $'...'là một chủ bashnghĩa tạo ra ...với các chuỗi thoát tiêu chuẩn được mở rộng. Th \'trước khi nó chỉ có nghĩa là một dấu chéo ngược sau khi kết thúc phần trích dẫn, chuỗi kết quả là s/ /\. (Có, bạn có thể chuyển trích dẫn ở giữa một chuỗi; nó không kết thúc chuỗi.)

Tiêu chuẩn POSIX sedchỉ chấp nhận \nnhư một phần của mẫu tìm kiếm. OS X sử dụng FreeBSD sed, tuân thủ nghiêm ngặt POSIX; GNU, như thường lệ, thêm các công cụ bổ sung và sau đó tất cả người dùng Linux đều nghĩ rằng đó là một loại "tiêu chuẩn" (có lẽ tôi sẽ ấn tượng hơn nếu một trong hai người có quy trình chuẩn).


Bây giờ tôi đã hiểu $'...'một phần. Nhưng ... là s/ /\ gì? Bạn có ý nghĩa switch quotinggì?
Ivan ZG Xiao

2
'...'là một loại trích dẫn vỏ; $'...'là một cái khác. Cũng có "..."\xđể trích dẫn một nhân vật duy nhất. Bạn có thể kết hợp những từ đó trong một từ duy nhất, đó là những gì đang được thực hiện ở đó, chuyển từ một ''chuỗi bình thường sang một $''chuỗi để dịch \n. Đối với phần còn lại, nó đang xây dựng một sedlệnh ( s/text/replacement/flags). Trong trường hợp này, lệnh được bắt đầu, bao gồm dấu gạch chéo ngược ở cuối để bảo vệ dòng mới theo nghĩa đen mà phần bổ sung $'\n/g'. Kết quả là thay thế tất cả các /gkhông gian ( cờ) bằng dòng mới.
geekizard

1

Có một thứ rất dễ nhìn thấy những gì đang xảy ra. Đơn giản chỉ cần lặp lại chuỗi!

echo 's/$/\'$'\n/g'

kết quả trong

s/$/\
/g

tương đương với s/$/\newline/g

Nếu bạn không có thêm \trước newline, shell sẽ hiểu newlinelà kết thúc của lệnh sớm.

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.