2009-05-25 28 views
53

Tôi cần phải thực hiện regex tìm và thay thế trên tất cả các tệp trong một thư mục (và các thư mục con của nó). Điều gì sẽ là lệnh shell linux để làm điều đó?sed người mới bắt đầu: thay đổi tất cả các lần xuất hiện trong một thư mục

Ví dụ: tôi muốn chạy điều này trên tất cả các tệp và ghi đè tệp cũ bằng văn bản mới, được thay thế.

sed 's/old text/new text/g' 
+0

http://theunixshell.blogspot.com/2012/12/find-and-replace-string-in-all-files.html – Vijay

Trả lời

82

Không có cách nào để làm điều đó chỉ sử dụng sed. Bạn cần sử dụng ít nhất tiện ích tìm kiếm cùng nhau:

find . -type f -exec sed -i.bak "s/foo/bar/g" {} \; 

Lệnh này sẽ tạo một tệp .bak cho mỗi tệp đã thay đổi.

Ghi chú:

  • Đối số -i cho sed lệnh là một phần mở rộng GNU, vì vậy, nếu bạn đang chạy lệnh này với BSD của sed bạn sẽ cần phải chuyển hướng đầu ra vào một tập tin mới sau đó đổi tên nó.
  • Tiện ích find không triển khai đối số -exec trong các hộp UNIX cũ, vì vậy, bạn sẽ cần phải sử dụng số | xargs thay thế.
0

Tôi có thể đề nghị (sau khi sao lưu tập tin của bạn):

find /the/folder -type f -exec sed -ibak 's/old/new/g' {} ';' 
-3

Có thể muốn thử my mass search/replace Perl script. Có một số ưu điểm so với các giải pháp hữu ích chuỗi (như không phải đối phó với nhiều mức độ giải thích metacharacter vỏ).

5

Vì tính di động, tôi không dựa vào các tính năng của sed dành riêng cho Linux hoặc BSD. Thay vào đó, tôi sử dụng tập lệnh overwrite từ cuốn sách của Kernighan và Pike trên Môi trường lập trình Unix.

Lệnh là sau đó

find /the/folder -type f -exec overwrite '{}' sed 's/old/new/g' {} ';' 

overwrite kịch bản (mà tôi sử dụng khắp nơi) là

#!/bin/sh 
# overwrite: copy standard input to output after EOF 
# (final version) 

# set -x 

case $# in 
0|1)  echo 'Usage: overwrite file cmd [args]' 1>&2; exit 2 
esac 

file=$1; shift 
new=/tmp/$$.new; old=/tmp/$$.old 
trap 'rm -f $new; exit 1' 1 2 15 # clean up files 

if "[email protected]" >$new    # collect input 
then 
    cp $file $old # save original file 
    trap 'trap "" 1 2 15; cp $old $file  # ignore signals 
      rm -f $new $old; exit 1' 1 2 15 # during restore 
    cp $new $file 
else 
    echo "overwrite: $1 failed, $file unchanged" 1>&2 
    exit 1 
fi 
rm -f $new $old 

Ý tưởng là nó ghi đè một tập tin duy nhất nếu một lệnh thành công. Hữu ích trong find và cũng là nơi bạn sẽ không muốn sử dụng

sed 's/old/new/g' file > file # THIS CODE DOES NOT WORK 

vì vỏ truncates các tập tin trước khi sed có thể đọc nó.

20

Tôi thích sử dụng find | xargs cmd hơn find -exec vì dễ nhớ hơn.

Ví dụ này trên toàn cầu thay thế "foo" với "thanh" trong file .txt bằng hoặc thấp hơn thư mục hiện tại của bạn:

find . -type f -name "*.txt" -print0 | xargs -0 sed -i "s/foo/bar/g" 

Các -print0-0 tùy chọn có thể được bỏ qua nếu tên tập tin của bạn không chứa các ký tự sôi nổi chẳng hạn như không gian.

+1

Nếu bạn đang sử dụng OSX, hãy thử 'tìm. -type f -name "* .txt" -print0 | xargs -0 sed -i '' "s/foo/bar/g" '(lưu ý cung cấp một chuỗi rỗng cho đối số' -i'). – jkukul

-4

Trong trường hợp tên tệp trong thư mục có một số tên thông thường (như tệp1, tệp2 ...) tôi đã sử dụng cho chu trình.

for i in {1..10000..100}; do sed 'old\new\g' 'file'$i.xml > 'cfile'$i.xml; done 
+0

điều này không liên quan đến câu hỏi được yêu cầu. Các câu hỏi không đề cập đến bất cứ điều gì về cùng một tên tập tin/thư mục mẫu. Hãy tránh những câu trả lời như vậy –

Các vấn đề liên quan