cờ in tại chỗ sed hoạt động cả trên Mac (BSD) và Linux


237

Có yêu cầu sedchỉnh sửa tại chỗ mà không cần sao lưu hoạt động cả trên Linux và Mac không? Mặc dù BSD sedđược cung cấp cùng với OS X dường như cần sed -i '' …, các sedbản phân phối GNU Linux thường đi kèm với việc diễn giải các trích dẫn dưới dạng tên tệp đầu vào trống (thay vì phần mở rộng sao lưu) và sed -i …thay vào đó cần .

Có bất kỳ cú pháp dòng lệnh nào hoạt động với cả hai hương vị, vì vậy tôi có thể sử dụng cùng một tập lệnh trên cả hai hệ thống không?


Là perl không phải là một lựa chọn? Bạn phải sử dụng sed?
Noufal Ibrahim

Có thể cài đặt phiên bản GNU và sử dụng nó! toporms.net/blog/2013/04/14/ trên ? Tôi sẽ thử nó trước. Sau đó, một lần nữa, loại hút quá.
Dmitry Minkovsky

2
@dimadima: Có thể thú vị với một số người khác đang duyệt câu hỏi này, những người có tập lệnh cá nhân vi phạm trên máy OS X của họ. Tuy nhiên, trong trường hợp của tôi, tôi cần nó cho hệ thống xây dựng của một dự án nguồn mở, trong đó việc bảo người dùng của bạn cài đặt GNU sed trước tiên sẽ đánh bại mục đích ban đầu của bài tập này (vá một vài tệp theo kiểu "hoạt động ở mọi nơi") .
dnadlinger

@klickverbot yeah, có ý nghĩa. Lần đầu tiên tôi đã thêm nhận xét dưới dạng câu trả lời, sau đó xóa nó, nhận ra đó không phải là câu trả lời cho câu hỏi của bạn :).
Dmitry Minkovsky

1
Tham khảo chéo: Làm thế nào để đạt được tính di động với sed -i (chỉnh sửa tại chỗ)? trên Sàn giao dịch ngăn xếp Unix & Linux.
MvG

Câu trả lời:


212

Nếu bạn thực sự muốn sử dụng sed -icách 'dễ dàng', các DOES sau hoạt động trên cả GNU và BSD / Mac sed:

sed -i.bak 's/foo/bar/' filename

Lưu ý thiếu không gian và dấu chấm.

Bằng chứng:

# GNU sed
% sed --version | head -1
GNU sed version 4.2.1
% echo 'foo' > file
% sed -i.bak 's/foo/bar/' ./file
% ls
file  file.bak
% cat ./file
bar

# BSD sed
% sed --version 2>&1 | head -1
sed: illegal option -- -
% echo 'foo' > file
% sed -i.bak 's/foo/bar/' ./file
% ls
file  file.bak
% cat ./file
bar

Rõ ràng sau đó bạn có thể xóa các .baktập tin.


2
Đây là con đường để đi. Thêm một vài ký tự, và nó di động. Xóa tệp sao lưu là chuyện nhỏ (bạn đã có tên tệp khi gọi sed)
slezica

Điều này hoạt động trên mac, nhưng trên Ubuntu 16.04, nó ghi đè tệp gốc thành 0 byte và tạo tệp .bak cũng bằng 0 byte?
nhà9

1
Lưu ý, trên macOS Sierra (và có thể sớm hơn, tôi không có máy tiện dụng), sedkhông chấp nhận commandđối số vị trí khi được gọi với -i- nó phải được cung cấp với một cờ khác , -e. Do đó, lệnh trở thành:sed -i.bak -e 's/foo/bar/' filename
ELLIOTTCABLE

5
Điều này tạo ra các bản sao lưu, trong khi OP đặc biệt yêu cầu chỉnh sửa tại chỗ.
Marc-André Lafortune

8
Vì vậy, giải pháp đầy đủ là:sed -i.bak 's/foo/bar/' file && rm file.bak
joeytwiddle

111

Điều này hoạt động với GNU sed, nhưng không phải trên OS X:

sed -i -e 's/foo/bar/' target.file
sed -i'' -e 's/foo/bar/' target.file

Điều này hoạt động trên OS X, nhưng không phải với GNU sed:

sed -i '' -e 's/foo/bar/' target.file

Trên OS X bạn

  • không thể sử dụng sed -i -evì phần mở rộng của tệp sao lưu sẽ được đặt thành-e
  • không thể sử dụng sed -i'' -echo cùng một lý do. Nó cần một khoảng trống giữa -i''.

1
@AlexanderMills Nói với sed rằng đối số tiếp theo là một lệnh - cũng có thể được bỏ qua ở đây.
Benjamin W.

4
Lưu ý rằng -i-i''giống hệt nhau tại thời gian phân tích cú pháp shell; sed không thể cư xử khác nhau trên hai lời mời đầu tiên, bởi vì nó có cùng lý lẽ.
wchargein

44

Khi ở OSX, tôi luôn cài đặt phiên bản GNU sed qua Homebrew, để tránh các sự cố trong tập lệnh, vì hầu hết các tập lệnh được viết cho phiên bản GNU sed.

brew install gnu-sed --with-default-names

Sau đó, sed BSD của bạn sẽ được thay thế bởi GNU sed.

Ngoài ra, bạn có thể cài đặt mà không có tên mặc định, nhưng sau đó:

  • Thay đổi của bạn PATHtheo hướng dẫn sau khi cài đặtgnu-sed
  • Kiểm tra tập lệnh của bạn để chọn giữa gsedhoặc sedtùy thuộc vào hệ thống của bạn

4
các --with-default-namesbị loại khỏi homebrew-core , thông tin thêm ở đây câu trả lời. khi cài đặt gnu-sedngay, hướng dẫn cài đặt chỉ định rằng bạn cần thêm gnubinvào PATH:PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"
pgericson

18

Như Noufal Ibrahim hỏi, tại sao bạn không thể sử dụng Perl? Bất kỳ máy Mac nào cũng sẽ có Perl và có rất ít bản phân phối Linux hoặc BSD không bao gồm một số phiên bản Perl trong hệ thống cơ sở. Một trong những môi trường duy nhất thực sự thiếu Perl sẽ là BusyBox (hoạt động như GNU / Linux -i, ngoại trừ không có phần mở rộng sao lưu nào có thể được chỉ định).

Như ismail khuyến nghị,

Vì perl có sẵn ở mọi nơi tôi chỉ cần làm perl -pi -e s,foo,bar,g target.file

và điều này có vẻ như là một giải pháp tốt hơn trong hầu hết mọi trường hợp so với các tập lệnh, bí danh hoặc các cách giải quyết khác để giải quyết sự không tương thích cơ bản sed -igiữa GNU / Linux và BSD / Mac.


Tôi thích giải pháp này. perllà một phần của đặc tả Cơ sở Tiêu chuẩn Linux kể từ ngày 1 tháng 5 năm 2009. refspecs.linuxfoundation.org/LSB_4.0.0/LSB-Lacular/iêu
OregonTrail

1
Đây dễ dàng là giải pháp tốt nhất cho tính di động
ecnepsnai

17

Không có cách nào để nó hoạt động.

Một cách là sử dụng một tệp tạm thời như:

TMP_FILE=`mktemp /tmp/config.XXXXXXXXXX`
sed -e "s/abc/def/" some/file > $TMP_FILE
mv $TMP_FILE some/file

Điều này hoạt động trên cả hai


Có lý do nào mà SOME_FILE = "$ (sed -s" s / abc / def / "some / file)"; tiếng vang "$ SOME_FILE"> some / file; thay vào đó sẽ không hoạt động
Jason Gross

Có vẻ như bạn sẽ bị giới hạn bởi kích thước tối đa của biến bash, phải không? Không chắc chắn nó sẽ hoạt động với các tập tin GB.
tương tự

3
Nếu bạn đang tạo một tệp tạm thời, tại sao không chỉ cung cấp tiện ích mở rộng để tạo tệp sao lưu (sau đó bạn có thể xóa) như @kine gợi ý bên dưới?
Alex Dupuy

13

Câu trả lời: Không.

Câu trả lời được chấp nhận ban đầu thực sự không làm những gì được yêu cầu (như đã lưu ý trong các bình luận). (Tôi đã tìm thấy câu trả lời này khi tìm kiếm lý do a file-exuất hiện "ngẫu nhiên" trong thư mục của mình.)

Rõ ràng là không có cách nào sed -iđể hoạt động ổn định trên cả MacOS và Linuces.

Khuyến nghị của tôi, cho những gì đáng giá, không phải là cập nhật tại chỗ với sed(có chế độ lỗi phức tạp), mà là tạo các tệp mới và đổi tên chúng sau đó. Nói cách khác: tránh -i.


9

Các -itùy chọn không phải là một phần của POSIX Sed . Một phương pháp di động hơn sẽ là sử dụng Vim trong chế độ Ex:

ex -sc '%s/alfa/bravo/|x' file
  1. % chọn tất cả các dòng

  2. s thay thế

  3. x lưu và đóng


Đây là câu trả lời chính xác. Một tính năng chính của POSIX là tính di động.
Kajukenbo

9

Đây là một phiên bản khác hoạt động trên Linux và macOS mà không cần sử dụng evalvà không phải xóa các tệp sao lưu. Nó sử dụng mảng Bash để lưu trữ các sedtham số, sạch hơn so với sử dụng eval:

# Default case for Linux sed, just use "-i"
sedi=(-i)
case "$(uname)" in
  # For macOS, use two parameters
  Darwin*) sedi=(-i "")
esac

# Expand the parameters in the actual call to "sed"
sed "${sedi[@]}" -e 's/foo/bar/' target.file

Điều này không tạo ra một tập tin sao lưu, cũng không phải là một tập tin có dấu ngoặc kép.


2
Đây là câu trả lời chính xác. Tôi sẽ đơn giản hóa nó một chút, nhưng ý tưởng hoạt động hoàn hảo sedi=(-i) && [ "$(uname)" == "Darwin" ] && sedi=(-i '') sed "${sedi[@]}" -e 's/foo/bar/' target.file
Alex Skrypnyk

Đồ tốt! Tôi thích phiên bản dài hơn cho dễ đọc, mặc dù.
nwinkler

1
Đây là cách tốt nhất để tôi tương thích với các hệ thống khác nhau.
Victor Choy

6

Câu trả lời của Steve Powell hoàn toàn chính xác, tham khảo trang MAN về sed trên OSX và Linux (Ubuntu 12.04) nêu bật tính không tương thích trong cách sử dụng sed 'tại chỗ' trên hai hệ điều hành.

JFYI, không nên có khoảng trắng giữa -i và bất kỳ dấu ngoặc kép nào (biểu thị phần mở rộng tệp trống) bằng phiên bản Linux của sed, do đó

sed Trang người đàn ông Linux

#Linux
sed -i"" 

trang người đàn ông OSX

#OSX (notice the space after the '-i' argument)
sed -i "" 

Tôi đã làm tròn điều này trong một tập lệnh bằng cách sử dụng lệnh bí danh và đầu ra tên hệ điều hành là ' uname ' trong một bash 'if'. Cố gắng lưu trữ các chuỗi lệnh phụ thuộc hệ điều hành trong các biến đã bị nhấn và bỏ lỡ khi diễn giải các trích dẫn. Việc sử dụng ' shopt -s extend_aliases ' là cần thiết để mở rộng / sử dụng các bí danh được xác định trong tập lệnh của bạn. sử dụng của shopt được giải quyết ở đây .


1

Nếu bạn cần thực hiện sedtại chỗ trong một bashtập lệnh và bạn KHÔNG muốn tại chỗ kết quả với các tệp .bkp và bạn có cách để phát hiện os (giả sử sử dụng Ostype.sh ), - thì hack sau với bashshell tích hợp evalsẽ hoạt động:

OSTYPE="$(bash ostype.sh)"

cat > myfile.txt <<"EOF"
1111
2222
EOF

if [ "$OSTYPE" == "osx" ]; then
  ISED='-i ""'
else # $OSTYPE == linux64
  ISED='-i""'
fi

eval sed $ISED 's/2222/bbbb/g' myfile.txt
ls 
# GNU and OSX: still only myfile.txt there

cat myfile.txt
# GNU and OSX: both print:
# 1111
# bbbb

# NOTE: 
# if you just use `sed $ISED 's/2222/bbbb/g' myfile.txt` without `eval`,
# then you will get a backup file with quotations in the file name, 
# - that is, `myfile.txt""`

0

Bạn có thể sử dụng bọt biển. Sponge là một chương trình unix cũ, được tìm thấy trong gói moreutils (cả trong ubfox và có lẽ là debian, và trong homebrew trong mac).

Nó sẽ đệm tất cả nội dung từ đường ống, đợi cho đến khi đường ống đóng (có thể có nghĩa là tệp đầu vào đã đóng) và sau đó ghi đè:

Từ trang người đàn ông :

Tóm tắc

tập tin '...' | grep '...' | tập tin bọt biển


3
Cách tiếp cận tuyệt vời - thật không may không thực sự giúp ích trong tình huống ban đầu vì lý do dùng đến sed là để sử dụng một tập lệnh trợ giúp đa nền tảng được sử dụng trên các máy khách, nơi bạn không thể phụ thuộc vào bất cứ điều gì khác ngoài hệ thống công cụ đang được cài đặt. Có thể hữu ích cho người khác, mặc dù.
dnadlinger

0

Các công việc sau đây đối với tôi trên Linux và OS X:

sed -i' ' <expr> <file>

ví dụ: đối với tệp fchứaaaabbaaba

sed -i' ' 's/b/c/g' f

mang lại lợi nhuận aaaccaacatrên cả Linux và Mac. Lưu ý có một chuỗi được trích dẫn chứa một khoảng trắng , không có khoảng trắng giữa -ichuỗi và chuỗi. Báo giá đơn hoặc đôi cả hai công việc.

Trên Linux, tôi đang sử dụng bashphiên bản 4.3.11 trong Ubuntu 14.04.4 và trên phiên bản Mac 3.2.57 trong OS X 10.11.4 El Capitan (Darwin 15.4.0).


1
Ồ, tôi rất vui vì tôi đã không nghe mọi người ở trên nói rằng điều đó là không thể và tiếp tục đọc! Điều này thực sự chỉ hoạt động. Cảm ơn!
Nhân viên

4
Không hoạt động với tôi trên Mac OS ... tệp mới có không gian được nối vào cuối tên tệp được tạo
Frédéric

Không hoạt động với tôi trên Mac (/ usr / bin / sed) - Bây giờ tôi có một tệp sao lưu bổ sung có khoảng
trắng được

Hãy thử lấy không gian ra khỏi dấu ngoặc đơn, nó hoạt động với tôi.
dps

0

Tôi gặp vấn đề này. Giải pháp nhanh chóng duy nhất là thay thế sed trong mac thành phiên bản gnu:

brew install gnu-sed

Điều này trùng lặp một câu trả lời hiện có với nhiều chi tiết hơn từ năm 2015.
tripleee 13/12/18
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.