Làm sed yêu cầu xác nhận trước mỗi lần thay thế?


37

Có cách nào để làm cho sed yêu cầu tôi xác nhận trước mỗi lần thay thế không? Một cái gì đó tương tự như 'c' khi sử dụng thay thế bên trong vim.

Liệu sed có làm điều này không?


3
Nó có thể về mặt kỹ thuật nhưng là một bài tập trí tuệ hơn là một nỗ lực hữu ích. Xem Làm thế nào để thay thế văn bản trong hệ thống phân cấp thư mục lớn? trong đó có giải pháp Vim và Perl.
Gilles 'SO- ngừng trở nên xấu xa'

Tôi đang sử dụng vim (args và argdo) bất cứ khi nào tôi cần 'xác nhận', nhưng tự hỏi liệu có cách nào 'đơn giản hơn'
Yuvi

1
Nó đi ngược lại mục đích cơ bản của sed - để tự động chỉnh sửa qua luồng.
teppic

@teppic không thực sự bởi vì bạn vẫn sẽ phải đi tìm các phiên bản trong tệp văn bản, điều mà sed có thể làm cho bạn. Tôi nghĩ rằng câu hỏi có ý nghĩa, chỉ trong trường hợp bạn thêm các tệp sai vào danh sách và muốn xem tệp nào bạn đang chỉnh sửa
Kolob Canyon

Câu trả lời:


37

Làm điều đó với sedcó lẽ sẽ không thể vì nó là một trình chỉnh sửa luồng không tương tác. Gói gọn sedtrong một kịch bản sẽ đòi hỏi quá nhiều suy nghĩ. Nó dễ dàng hơn để làm điều đó với vim:

vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' file.in

Vì nó đã được đề cập trong các bình luận bên dưới, đây là cách nó sẽ được sử dụng trên nhiều tệp khớp với một mẫu tên tập tin cụ thể trong thư mục hiện tại:

for fname in file*.txt; do
    vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' "$fname"
done

Hoặc, nếu trước tiên bạn muốn đảm bảo rằng tệp thực sự chứa một dòng khớp với mẫu đã cho trước, trước khi thực hiện thay thế,

for fname in file*.txt; do
    grep -q 'PATTERN' "$fname" &&
    vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' "$fname"
done

Hai vòng lặp shell ở trên được sửa đổi thành findcác lệnh thực hiện cùng một thứ nhưng đối với tất cả các tệp có tên cụ thể ở đâu đó trong hoặc dưới một số top-dirthư mục,

find top-dir -type f -name 'file*.txt' \
    -exec vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' {} \;
find top-dir -type f -name 'file*.txt' \
    -exec grep -q 'PATTERN' {} \; \
    -exec vim -c '%s/PATTERN/REPLACEMENT/gc' -c 'wq' {} \;

Hoặc, sử dụng các vòng lặp shell ban đầu và có findtên đường dẫn nguồn cấp dữ liệu vào chúng:

find top-dir -type f -name 'file*.txt' -exec sh -c '
    for pathname do
        vim -c "%s/PATTERN/REPLACEMENT/gc" -c "wq" "$pathname"
    done' sh {} +
find top-dir -type f -name 'file*.txt' -exec sh -c '
    for pathname do
        grep -q "PATTERN" "$pathname" &&
        vim -c "%s/PATTERN/REPLACEMENT/gc" -c "wq" "$pathname"
    done' sh {} +

Bạn làm gì, trong mọi trường hợp, không muốn làm một cái gì đó giống như for filename in $( grep -rl ... )từ

  1. nó sẽ yêu cầu grepkết thúc chạy trước cả khi bắt đầu vòng lặp đầu tiên, không liên tục
  2. tên đường dẫn được trả về grepsẽ được chia thành các từ trên khoảng trắng và những từ này sẽ trải qua tên tập tin toàn cầu (điều này không đủ tiêu chuẩn tên đường dẫn chứa khoảng trắng và ký tự đặc biệt).

Liên quan:


2
Ưu điểm sedlà nó có thể hoạt động trên nhiều tệp, ví dụ, sed -i 's/old/new/g' /path/to/*.txthoặc một cái gì đó tương tự.
dùng1717828

10
for i in $(grep -rl "old"); do vim -c "%s/old/new/gc" -c "wq" "$i"; done
tcpaiva

@tecepe, vui lòng chuyển đổi nó thành một câu trả lời, Cảm ơn bạn.
Nishant

1
@Nishant Đó sẽ là một câu trả lời mong manh vì nó sẽ không đủ tiêu chuẩn cho bất kỳ tệp nào chứa khoảng trắng trong tên hoặc đường dẫn của nó.
Kusalananda

7

Bạn có thể có được điều này bằng cách làm như vậy:

:%s/OLD_TEXT/NEW_TEXT/gc

Cụ thể, thêm cdấu phân cách thứ ba.

Lưu ý rằng tùy chọn 'c' chỉ hoạt động trong Vim; bạn sẽ không thể sử dụng nó với seddòng lệnh.


4
Để làm rõ: điều này chỉ hoạt động trong Vim, không phải dòng lệnh thông thường sed.
Brendan

OP được gắn thẻ vim, vì vậy câu trả lời này được áp dụng; mặc dù, rõ ràng vim và sed có những khả năng khác nhau
ILMostro_7


-1
searchandreplace () {
if [ -z $2 ] ; then
    realpath * | xargs grep -ins --directories=skip --color=always "$1" | nl -s "."
else
    realpath * | xargs grep -ins --directories=skip --color=always "$1" | nl -s "."
    exp=$(realpath * | xargs grep -ins --directories=skip --color=never "$1" | cut -d':' -f1,2 | awk -F':' '{print $2 $1}' | sed -E "s|^[0-9]+|sed -i \'&s/|; s|//|/"$1"/"$2"/g\' /|")
    IFS=$'\n'
    for d in $exp
        do
        read -p "Exec $(echo -e -n "\033[1;31m$d\033[0m")? " -e REP
            if [ "$REP" = y ]; then
            echo `bash -c $d`;
            fi
    done
fi
}

Nếu bạn cung cấp searchandreplace "AAA"chuỗi này với một đối số duy nhất - - nó chỉ tìm kiếm chuỗi đó trong thư mục hiện tại, nhưng nếu bạn cung cấp chuỗi đó bằng các đối số kép searchandreplace AAA BBB- thì ngoài các đối số trên, nó cũng yêu cầu bạn thay thế dòng đầu tiên bằng dòng thứ hai dòng "cho mỗi dòng.

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.