Làm thế nào để báo cáo thay đổi tại chỗ


23

Khi sử dụng sedđể thay thế các chuỗi tại chỗ, có cách nào để làm cho nó báo cáo các thay đổi mà nó thực hiện (mà không phụ thuộc vào sự khác biệt của các tệp cũ và mới) không?

Chẳng hạn, làm thế nào tôi có thể thay đổi dòng lệnh

find . -type f | xargs sed -i 's/abc/def/g'

Vì vậy, tôi có thể thấy những thay đổi được thực hiện trên bay?

Câu trả lời:


15

Bạn có thể sử dụng sed's wcờ với một trong hai /dev/stderr, /dev/tty, /dev/fd/2nếu được hỗ trợ trên hệ thống của bạn. Ví dụ: với một đầu vào filenhư:

foo first
second: missing
third: foo
none here

đang chạy

sed -i '/foo/{
s//bar/g
w /dev/stdout
}' file

đầu ra:

bar first
third: bar

mặc dù filenội dung đã được thay đổi thành:

bar first
second: missing
third: bar
none here

Vì vậy, trong trường hợp của bạn, chạy:

find . -type f -printf '\n%p:\n' -exec sed -i '/foo/{
s//bar/g
w /dev/fd/2
}' {} \;

sẽ chỉnh sửa các tập tin tại chỗ và đầu ra:

./file1:
thanh công cụ
thêm thanh

./file2:

./file3:
thanh đầu tiên
thứ ba: thanh

Bạn cũng có thể in một cái gì đó như original line >>> modified line:

find . -type f -printf '\n%p:\n' -exec sed -i '/foo/{
h
s//bar/g
H
x
s/\n/ >>> /
w /dev/fd/2
x
}' {} \;

chỉnh sửa các tập tin tại chỗ và đầu ra:

./file1:
công cụ foo >>> công cụ thanh
thêm foo >>> thêm thanh

./file2:

./file3:
foo đầu tiên >>> thanh đầu tiên
thứ ba: foo >>> thứ ba: thanh

16

Bạn có thể thực hiện trong hai lượt bằng cách sử dụng phành động rint trên đường chuyền đầu tiên với:

find . -type f | xargs sed --quiet 's/abc/def/gp'

trong đó --quietlàm cho sed không hiển thị mọi dòng và phậu tố chỉ hiển thị các dòng mà sự thay thế đã khớp.

Điều này có giới hạn đó sed sẽ không hiển thị trong đó các file đang được thay đổi trong đó tất nhiên có thể được cố định với một số phức tạp thêm.


Nó không hoàn toàn làm những gì tôi muốn vì bạn cần hai lượt, nhưng tôi đang bỏ phiếu vì tôi mới học được điều này và nó rất hữu ích. Đặc biệt là, như bạn đã nói, các tập tin cũng được in. Một cái gì đó giống nhưfor x in `find . -type f`; do echo ///File $x: ; sed --quiet 's/abc/def/gp' $x; done
ricab

@msw Tôi có nhiều sedbiểu hiện, tôi không muốn viết /gpcho từng người. Làm thế nào để thiết lập nó trên toàn cầu?
alrcal

8

Tôi không nghĩ điều đó là có thể, nhưng một cách giải quyết khác có thể là sử dụng perl thay thế:

find . -type f | xargs perl -i -ne 's/abc/def/ && print STDERR' 

Điều này sẽ in các dòng thay đổi thành lỗi tiêu chuẩn. Ví dụ:

$ cat foo
fooabcbar
$ find . -type f | xargs perl -i -ne 's/abc/def/ && print STDERR' 
foodefbar

Bạn cũng có thể làm cho điều này phức tạp hơn một chút, in số dòng, tên tệp, dòng gốc và dòng thay đổi:

$ find . -type f | 
   xargs perl -i -ne '$was=$_; chomp($was);
                      s/abc/def/ && print STDERR "$ARGV($.): $was : $_"' 
./foo(1): fooabcbar : foodefbar

+1 Bạn cũng có thể sử dụng $ARGVtên của tệp đang được vận hành.
Joseph R.

@JosephR. điểm tốt, thêm vào.
terdon

Cảm ơn, điều đó có thể hữu ích (không tự mình kiểm tra). Tôi không chọn vì nó không sử dụng sed, vì vậy nó không trả lời chính xác câu hỏi.
ricab

@ricab không sao, bạn không nên chấp nhận câu trả lời trừ khi nó thực sự trả lời câu hỏi của bạn. Hãy nhớ rằng mặc dù đối với những điều đơn giản như thế này, perlcú pháp của nó rất giống với sedvà tôi không nghĩ những gì bạn yêu cầu thực sự có thể với sed.
terdon

3

Có thể sử dụng cờ w ghi mẫu hiện tại vào một tệp. Vì vậy, bằng cách thêm nó vào lệnh thay thế, chúng ta có thể báo cáo các thay thế liên tiếp vào một tệp và in nó sau khi hoàn thành công việc. Tôi cũng thích tô màu chuỗi thay thế bằng grep.

sed -i -e "s/From/To/gw /tmp/sed.done" file_name
grep --color -e "To" /tmp/sed.done

Lưu ý rằng chỉ có một khoảng trắng giữa w và tên tệp của nó.

Điều này thậm chí còn tốt hơn diff, vì diffing cũng có thể cho thấy những thay đổi ngay cả khi chúng không được tạo ra bởi sed.


Chỉ cần thử nghiệm nó và sed chỉ viết những dòng mà nó thay thế sed.done. Do đó, các dòng có "To" trong tệp gốc không được in ra sed.done, do đó khi grep "To" sed.donebạn sẽ chỉ thấy các dòng được thay đổi bởi sed. Bạn sẽ không thấy dòng gốc trong tệp trước khi nó được thay thế, nếu đó là những gì bạn đang nhắm đến ...
aairey

1

Tôi thích giải pháp @terdon - perl rất tốt cho việc này.

Đây là phiên bản tinh chỉnh của tôi rằng:

  • sẽ không cố gắng thay đổi các tệp không có chuỗi phù hợp
  • sẽ sao lưu phiên bản trước của các tệp thay đổi (tạo phiên bản .bak)
  • sẽ liệt kê mọi tệp / lineno đã thay đổi và hiển thị các phiên bản OLD và MỚI của dòng đó được thụt vào và bên dưới để dễ đọc

find /tmp/test -type f ! -name "*.bak" -exec grep -l '/opt/gridmon' {} \; | xargs -L1 perl -ni'.bak' -e'$old=$_; s/\/opt\/gridmon/~/g && print STDERR "$ARGV($.):\n\tOLD:$old\tNEW:$_"'

đầu ra ví dụ

/tmp/test/test4.cfg(13):
    OLD:    ENVFILE /opt/gridmon/server/etc/gridmonserver.cfg
    NEW:    ENVFILE ~/server/etc/gridmonserver.cfg
/tmp/test/test4.cfg(24):
    OLD:    ENVFILE /opt/gridmon/server/etc/gridmonserver.cfg
    NEW:    ENVFILE ~/server/etc/gridmonserver.cfg
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.