grep đường ống vào sed, thay thế nội tuyến; nhưng tôi muốn sed in tên tệp và thay đổi dòng. Có thể không?


7

Đây là lệnh của tôi (phá vỡ chủ ý):

grep FOO "/Users/gjtorikian/blah" -l | xargs sed -i '' '/FOO/{s/FOO/BAR/g; w /dev/stdout
}'

Ở cấp độ cao: grepcho FOO trong blahthư mục; ống chỉ trong tên tệp (vì -l) đến sed; sedthực hiện thay thế nội tuyến ( -i '') và chỉ in thuật ngữ đã thay đổi thành /dev/stdout.

Nếu tôi bỏ qua -lđường ống và đường ống, tôi sẽ lấy lại từ grep:

/Users/gjtorikian/blah/baz.cs:1:FOO
/Users/gjtorikian/blah/bar.js:1:FOO

Những gì tôi muốn là sedthực hiện thay thế nội tuyến, và sau đó hiển thị cho tôi các tập tin và thuật ngữ thay thế; ví dụ:

/Users/gjtorikian/blah/baz.cs:1:BAR
/Users/gjtorikian/blah/bar.js:1:BAR

Là một điều như vậy có thể? Nếu nó quan trọng, tôi chỉ muốn giữ nó với grep/ sed. Tôi có phải làm một giây grepsau sedkhông?


Tôi không thấy một cách để có được tên tệp hiện tại trong sed, vì vậy bạn có thể sẽ cần một grep thứ hai.
Kevin

Ngoài ra, bạn không cần '', đó là mặc định.
Kevin

3
Trên OS X, ''không phải là mặc định.
gjtorikian

Câu trả lời:


4

Một khả năng sẽ là chuyển đầu ra của grepmột sedbộ lọc riêng .

grep -l FOO "/Users/gjtorikian/blah/"* |
{ tee /dev/fd/3 |
  xargs sed -i -e '/FOO/{' -e 's/FOO/BAR/g' -e 'w /dev/stdout'
} 3>&1 | sed 's/:FOO$/:BAR/'

Bạn có thể thực hiện sedin số dòng (bằng =lệnh) khi tìm thấy kết quả khớp và thực hiện xử lý hậu kỳ.

Có lẽ sẽ rõ ràng hơn khi sử dụng awk.

for x in "/Users/gjtorikian/blah/"*; do
  awk '
    sub(/FOO/, "BAR") {found=1; print FILENAME ":" NR ":" "BAR" >"/dev/stderr"}
    1 {print}
    END {exit(!found)}
' "$x" >"$x.tmp" && mv "$x.tmp" "$x"
done

2

Vì tôi không phải là người nói tiếng Anh bản địa nên có lẽ tôi đã không hiểu.

Để 'grep' một thư mục bạn cần '-r'. Việc sử dụng '-l' chỉ in tên tệp và nó dừng lại sau khi xuất hiện lần đầu tiên.

# pattern=/home ; grep -l "$pattern" /etc/[a-z]* 2>/dev/null | while read line ; do echo "$line:$pattern" ; done
/etc/adduser.conf:/home
/etc/fstab:/home
/etc/fstab~:/home
/etc/libuser.conf:/home
/etc/mpd.conf:/home
/etc/mpd.conf~:/home
/etc/mtab:/home
/etc/netscsid.conf:/home
/etc/passwd:/home
/etc/passwd-:/home
/etc/sudoers:/home
/etc/sudoers.tmp~:/home

1

Tôi nghĩ rằng bạn đang làm cho vấn đề trở nên quá phức tạp bằng cách cố gắng thực hiện nó trong một lần. Bạn chỉ đơn giản là có thể làm một

grep -H -n /Users/gjtorikian/blah | sed 's/\(^.*?:[0-9]+?:\).*FOO.*/\1BAZ/'

để có được danh sách các tệp có số dòng và thay thế (điều này sẽ hoạt động, miễn là tên tệp của bạn không chứa dấu hai chấm, nhưng dù sao đó cũng là một ý tưởng tồi trong Mac OS ...). Sau đó, bạn có thể phát hành một

sed -i '' 's/FOO/BAR/g' /Users/gjtorikian/blah

Không có grep và xarg là cần thiết ở đây (bạn có thể thực hiện "tìm ... | xarg" nếu bạn có rất nhiều tệp). Nếu bạn lo lắng về sự trùng lặp, bạn có thể đặt hai dòng thành tập lệnh hoặc hàm và thực hiện thay thế biến ở đó.


sed -i ...thay đổi filetimes ngay cả khi luồng không thay đổi.

@jww: bạn nói đúng, đó là vì sedtrình chỉnh sửa luồng không phải là trình chỉnh sửa tệp, do đó -itùy chọn vi phạm triết lý unix ( mywiki.wooledge.org/BashFAQ/021#Using_nonstiteria_tools ). Nếu bạn muốn tránh sử dụng ex(ví dụ ex -sc '%s/FOO/BAR/ge|x' /Users/gjtorikian/blah).
David Ongaro

1

Thay thế đệ quy FOO bằng BAR trong thư mục hiện tại (chế độ im lặng)

grep -rl 'FOO' | xargs sed -i 's/FOO/BAR/'

0

Lót

grep -n FOO * -R|awk -F\: '{ print $1 }'|sort|uniq|while read file; do sed -i 's/FOO/BAR/g' $file; done
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.