Lưu sửa đổi tại chỗ với awk


135

Tôi đang tìm hiểu awkvà tôi muốn biết nếu có một tùy chọn để viết các thay đổi vào tệp, tương tự như sednơi tôi sẽ sử dụng -itùy chọn để lưu các sửa đổi vào một tệp.

Tôi hiểu rằng tôi có thể sử dụng chuyển hướng để viết các thay đổi. Tuy nhiên, có một lựa chọn awkđể làm điều đó?


Ngoài ra, hãy xem serverfault.com/a/547331/313521 để biết câu trả lời tổng quát hơn về "chỉnh sửa tệp tại chỗ bằng chuyển hướng".
tự đại diện

@ Thẻ con. Các giải pháp có mong manh khủng khiếp. Hoàn toàn không có gì đảm bảo về thứ tự các sự kiện và sử dụng giải pháp đó có thể cắt bớt dữ liệu của bạn. Bên cạnh đó, tôi không thể nhận xét trực tiếp trên trang web đó vì tôi cần 50 đại diện trên trang đó để làm như vậy. Tôi sẽ không bao giờ hiểu tại sao SO phân mảnh thành Unix / Linux và quản trị viên máy chủ, et al. IMO, đó là một sai lầm.
William Pursell

@WilliamPursell, "không đảm bảo về thứ tự các sự kiện" thực sự sai. Sự mong manh duy nhất mà giải pháp có được là nếu độ dài của nội dung lớn hơn độ dài tối đa cho một lệnh. Thứ tự của các sự kiện, tuy nhiên, được đảm bảo.
tự đại diện

@Wildcard Tiêu chuẩn nào đảm bảo cho việc đặt hàng?
William Pursell

@WilliamPursell nó được đảm bảo bởi tài liệu bash. Đối với các vỏ khác tôi không biết. (Nhân tiện, nếu bạn liên kết tài khoản của mình, bạn sẽ có 100 phần thưởng liên kết đại diện và sẽ có thể nhận xét.)
Wildcard

Câu trả lời:


141

Trong GNU Awk mới nhất (kể từ phiên bản 4.1.0 ), nó có tùy chọn chỉnh sửa tệp "tại chỗ" :

[...] Phần mở rộng "tại chỗ", được xây dựng bằng cơ sở mới, có thể được sử dụng để mô phỏng sed -itính năng GNU " ". [...]

Ví dụ sử dụng:

$ gawk -i inplace '{ gsub(/foo/, "bar") }; { print }' file1 file2 file3

Để giữ bản sao lưu:

$ gawk -i inplace -v INPLACE_SUFFIX=.bak '{ gsub(/foo/, "bar") }
> { print }' file1 file2 file3

1
@sudo_O - Cảm ơn bạn đã trình diễn "tại chỗ". Nâng cao câu trả lời của bạn!
lind

Hình như tùy chọn có thể đã được gỡ bỏ? Với 4.1.3, tôi có "-i bao gồm cả - bao gồm = bao gồm"
Keith Hughitt

1
@Keith tôi đã có cùng một câu hỏi. Tôi vừa thử nó và nó hoạt động trên 4.1.3 của tôi. inplacethực sự là một thư viện được bao gồm gawktheo câu trả lời của iiSeymour , vì vậy đây inplacelà một cái gì đó có thể được bao gồm như một includefile.
cxw

Một cảnh báo quan trọng ở đây: mảng 'nhìn thấy' sẽ lấp đầy với các dòng trùng lặp từ TẤT CẢ các tệp có trong lệnh. Vì vậy, nếu mỗi tệp có ví dụ như một tiêu đề chung, nó sẽ bị xóa trong mọi tệp sau tệp đầu tiên. Thay vào đó, nếu bạn muốn xử lý từng tệp một cách độc lập, bạn sẽ cần phải làm một cái gì đó như cho f trong * .txt; làm gawk -i tại chỗ '! thấy [$ 0] ++' "$ f"; xong
Nick K9

135

Trừ khi bạn có GNU awk 4.1.0 trở lên ...

Bạn sẽ không có tùy chọn như -itùy chọn của sed nên thay vào đó:

$ awk '{print $0}' file > tmp && mv tmp file

Lưu ý: đó -ikhông phải là phép thuật, nó cũng đang tạo một tệp tạm thời sedchỉ xử lý nó cho bạn.


Kể từ GNU awk 4.1.0 ...

GNU awkđã thêm chức năng này trong phiên bản 4.1.0 (phát hành 10/05/2013) . Nó không phải là chuyển tiếp thẳng như chỉ đưa ra -itùy chọn như được mô tả trong các ghi chú được phát hành:

Tùy chọn -i mới (từ xgawk) được sử dụng để tải các tệp thư viện awk. Điều này khác với -f ở chỗ đối số không phải tùy chọn đầu tiên được coi là tập lệnh.

Bạn cần sử dụng inplace.awktệp bao gồm kèm theo để gọi tiện ích mở rộng đúng cách như sau:

$ cat file
123 abc
456 def
789 hij

$ gawk -i inplace '{print $1}' file

$ cat file
123
456
789

Biến INPLACE_SUFFIXcó thể được sử dụng để chỉ định phần mở rộng cho tệp sao lưu:

$ gawk -i inplace -v INPLACE_SUFFIX=.bak '{print $1}' file

$ cat file
123
456
789

$ cat file.bak
123 abc
456 def
789 hij

Tôi rất vui vì tính năng này đã được thêm vào nhưng với tôi, việc triển khai không quá khủng khiếp vì sức mạnh đến từ sự đơn giản của ngôn ngữ và imo-i inplace dài 8 ký tự .

Đây là một liên kết đến hướng dẫn cho từ chính thức.


Chẳng phải ví dụ 'đầu tiên' của bạn sẽ giống như : awk '{ gsub(/foo/, "bar" ) } ; { print $0 }' file > tmp.txt && mv -v tmp.txt file?
Tony Barganski

Thật ngạc nhiên, kể từ tháng 4 năm 2019, vẫn ở gawk 4.0.2. Đừng để ai nói với bạn như vậy và phiên bản như vậy sẽ có sẵn.
John Lunzer

Litte ngắn hơn awk '{print $0}' file | sponge filesử dụng spongetừ moreutils.
brablc

15

@sudo_Ocâu trả lời đúng .

Điều này không thể làm việc:

someprocess < file > file

Shell thực hiện các chuyển hướng trước khi chuyển giao quyền điều khiển cho someprocess ( chuyển hướng ). Việc >chuyển hướng sẽ cắt tập tin thành kích thước không ( chuyển hướng đầu ra ). Do đó, tại thời điểm someprocess được khởi chạy và muốn đọc từ tệp, không có dữ liệu nào để đọc.


14

chỉ cần một chút hack hoạt động

echo "$(awk '{awk code}' file)" > file

Hoạt động như một lá bùa! Nhưng có thể lưu lệnh awk thành biến và chỉ sử dụng nó trong thủ thuật tiện lợi của bạn?
ashrasmun

12

Một cách khác là sử dụng sponge:

awk '{print $0}' your_file | sponge your_file

Nơi bạn thay thế '{print $0}'bằng tập lệnh awk của bạn và your_filebằng tên của tệp bạn muốn chỉnh sửa tại chỗ.

sponge hấp thụ hoàn toàn đầu vào trước khi lưu nó vào tập tin.


Làm thế nào tiêu chuẩn / di động là bọt biển?
Thomas

2
spongelà một phần của moreutils. Vì vậy, nó sẽ không có mặt theo mặc định trong hầu hết các hệ thống. Nhưng có vẻ như ít nhất spongebản thân nó là đủ di động và có thể chạy gần như mọi nơi.
MarSoft

1
Nhược điểm của giải pháp này so với teedựa trên cơ sở là spongesẽ đọc mọi thứ vào RAM trước khi ghi xuống, do đó nó sẽ đóng băng trên các tệp lớn.
MarSoft

5

sau sẽ không làm việc

echo $(awk '{awk code}' file) > file

cái này nên hoạt động

echo "$(awk '{awk code}' file)" > file

3

Trong trường hợp bạn muốn một giải pháp chỉ awk mà không tạo tệp tạm thời và có thể sử dụng được với phiên bản! = (Gawk 4.1.0):

awk '{a[b++]=$0} END {for(c=0;c<=b;c++)print a[c]>ARGV[1]}' file

4
Nhưng điều này có đệm toàn bộ tập tin vào bộ nhớ? Hãy xem xét một tệp 20 GB.
Amit N Nikol

0

Sử dụng tee

 awk '{awk code}' file | tee file

các teevị trí lệnh cất và thực hiện sau khi awklệnh được hoàn thành do sự |.


5
Điều này là không đúng. Hai lệnh được thực thi song song và dữ liệu ngay lập tức được truyền qua đường ống. Bất kỳ tệp nào lớn hơn bộ đệm (8192 byte trên máy của tôi) sẽ bị cắt ngắn và bạn sẽ mất dữ liệu.
tripflag
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.