gawk inplace và stdout


10

Có thể sử dụng tùy chọn gawkcủa mình -i inplacevà cũng có thể in mọi thứ stdoutkhông?

Ví dụ: nếu tôi muốn cập nhật một tệp và nếu có bất kỳ thay đổi nào, hãy in tên của tệp và các dòng đã thay đổi để stderrtôi có thể làm một cái gì đó như

find -type f -name 'myfiles' -exec gawk -i inplace '{if(gsub(/pat/, "repl")) { print FILENAME > "/proc/self/fd/2" ; print > "/proc/self/fd/2"; } print;}' {} +

nhưng có cách nào để sử dụng stdoutthay thế, hoặc cách sạch hơn để in khối đó sang luồng thay thế?


2
Trong trường hợp cụ thể này, bạn có thể muốn chạy một cái gì find -type f -name 'myfiles' -exec grep -q 'pattern' {} \; -print -exec gawk -i inplace '{do_your_sub_and_print_to_dev/stderr_too}' {} \;đó theo cách đó, bạn sẽ chỉ sử dụng awk để chỉnh sửa các tệp thực sự chứa các dòng khớp với mẫu đó.
don_crissti

@don_crissti Tôi thường quên mất grepcó thể nhanh hơn bao nhiêu . Bản năng đầu tiên của tôi là tránh phải "xử lý" tệp hai lần, nhưng tôi sẽ không ngạc nhiên nếu nó thực sự nhanh hơn dù sao. Nó chỉ cho thấy lý do tại sao tôi có thể tin vào ruột của mình vào các nhiệm vụ hồ sơ
Eric Renouf

1
Có, nó khá nhanh và hãy nhớ rằng: 1) nếu không có kết quả khớp, bạn chỉ xử lý tệp một lần (phần -print -exec gawkkhông được thực hiện nữa) và 2) nó sẽ dừng ở trận đấu thứ nhất vì vậy trừ khi trận đấu thứ nhất diễn ra dòng cuối cùng bạn vẫn không xử lý toàn bộ tệp hai lần (giống như gấp 1 lần). Ngoài ra, nếu gawk -i inplacehoạt động như sed -inó sẽ chỉnh sửa tệp tại chỗ bằng mọi cách - tức là cập nhật dấu thời gian, inode, vv ngay cả khi không có gì để chỉnh sửa ...
don_crissti

Câu trả lời:


13

Bạn nên sử dụng /dev/stderrhoặc /dev/fd/2thay vì /proc/self/fd/2. gawkxử lý /dev/fd/x/dev/stderrcủa chính nó (cho dù hệ thống có các tập tin hay không).

Khi bạn làm một:

print "x" > "/dev/fd/2"

gawklàm một write(2, "x\n"), trong khi bạn làm:

print "x" > "/proc/self/fd/2"

vì nó không được đối xử /proc/self/fd/xđặc biệt, nên nó thực hiện:

fd = open("/proc/self/fd/2", O_WRONLY|O_CREAT|O_TRUNC);
write(fd, "x\n");

Đầu tiên /proc/self/fdlà Linux cụ thể và trên Linux họ có vấn đề. Hai phiên bản trên không tương đương khi stderr là một tệp thông thường hoặc có thể tìm kiếm khác hoặc với một ổ cắm (mà cái sau sẽ thất bại) (không đề cập đến việc nó lãng phí một bộ mô tả tệp).

Điều đó đang được nói, nếu bạn cần viết vào thiết bị xuất chuẩn ban đầu, bạn cần lưu nó đi trong một fd khác như:

gawk -i inplace '{
   print "goes into the-file"
   print "to stdout" > "/dev/fd/3"}' the-file 3>&1

gawkkhông chuyển hướng thiết bị xuất chuẩn với vị trí vào tệp. Nó cần thiết bởi vì, ví dụ, bạn muốn:

awk -i inplace '{system("uname")}' file

để lưu trữ unameđầu ra vào file.


2

Chỉ để cho vui, một cách tiếp cận thay thế chỉ sử dụng POSIX tính năng của find, sh, grepvà (đáng chú ý nhất) ex:

find . -type f -name 'myfiles' -exec sh -c '
  for f do grep -q "pat" "$f" &&
    { printf "%s\n" "$f";
      printf "%s\n" "%s/pat/repl/g" x | ex "$f";
  }; done' find-sh {} +

(Tất cả các ngắt dòng trong lệnh trên là tùy chọn; nó có thể được cô đọng thành một lớp lót.)

Hoặc, được cho là rõ ràng hơn:

find . -type f -name 'myfiles' -exec sh -c '
  for f
  do
    if grep -q "pat" "$f"; then
      printf "%s\n" "$f"
      printf "%s\n" "%s/pat/repl/g" x | ex "$f"
    fi
  done' find-sh {} +

:)


(Lệnh này chưa được kiểm tra; chỉnh sửa được hoan nghênh nếu tôi thực hiện bất kỳ mục đích nào.)

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.