บันทึกการแก้ไขในสถานที่ด้วย awk


140

ฉันกำลังเรียนรู้awkและต้องการทราบว่ามีตัวเลือกในการเขียนการเปลี่ยนแปลงในไฟล์หรือไม่คล้ายกับsedที่ฉันจะใช้-iตัวเลือกเพื่อบันทึกการแก้ไขลงในไฟล์

ฉันเข้าใจว่าฉันสามารถใช้การเปลี่ยนเส้นทางเพื่อเขียนการเปลี่ยนแปลงได้ อย่างไรก็ตามมีทางเลือกในawkการทำเช่นนั้นหรือไม่?


เผื่อว่าใครอยากได้ inplace save ด้วย NON GNU awkสามารถใช้ลิงค์ต่อไปนี้ได้เช่นกันstackoverflow.com/questions/59243104/…ได้ โปรด
RavinderSingh13

คำตอบ:


150

ใน GNU Awk 4.1.0 (เผยแพร่ 2013) และใหม่กว่าจะมีตัวเลือกในการแก้ไขไฟล์ "inplace" :

[... ] ส่วนขยาย "inplace" ซึ่งสร้างขึ้นโดยใช้สิ่งอำนวยความสะดวกใหม่สามารถใช้เพื่อจำลองsed -iคุณลักษณะ " " ของ GNU ได้ [... ]

ตัวอย่างการใช้งาน:

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

ในการสำรองข้อมูล:

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

ดูเหมือนว่าตัวเลือกอาจถูกลบไปแล้ว? ด้วย 4.1.3 ฉันมี "-i includefile --include = includefile"
Keith Hughitt

1
@Keith ฉันมีคำถามเดียวกัน ฉันเพิ่งลองใช้และใช้งานได้กับ 4.1.3 ของฉัน inplaceเป็นจริงห้องสมุดพร้อมกับgawkตามคำตอบ iiSeymour ของจึงเป็นสิ่งที่สามารถนำมารวมเป็นinplace includefile
cxw

ข้อแม้สำคัญที่นี่: อาร์เรย์ 'เห็น' จะเต็มไปด้วยบรรทัดที่ซ้ำกันจากไฟล์ทั้งหมดที่รวมอยู่ในคำสั่ง ดังนั้นหากแต่ละไฟล์มีเช่นส่วนหัวทั่วไปไฟล์นั้นจะถูกลบออกในทุกไฟล์หลังจากไฟล์แรก ถ้าคุณต้องการจัดการแต่ละไฟล์แยกกันคุณจะต้องทำบางอย่างเช่นสำหรับ f ใน * .txt; ทำ gawk -i inplace '! seen [$ 0] ++' "$ f"; done
Nick K9

140

เว้นแต่คุณจะมี GNU awk 4.1.0 หรือใหม่กว่า ...

คุณจะไม่มีตัวเลือกเช่น-iตัวเลือกของ sed ให้ทำ:

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

หมายเหตุ: -iไม่ใช่เวทมนตร์ แต่ยังสร้างไฟล์ชั่วคราวที่sedจัดการให้คุณ


ณ GNU awk 4.1.0 ...

GNU awkเพิ่มฟังก์ชั่นนี้ในรุ่น 4.1.0 (ปล่อย 2013/10/05) มันไม่ตรงไปข้างหน้าเหมือนการให้-iตัวเลือกตามที่อธิบายไว้ในบันทึกย่อที่เผยแพร่:

อ็อพชัน -i ใหม่ (จาก xgawk) ใช้สำหรับการโหลดไฟล์ไลบรารี awk สิ่งนี้แตกต่างจาก -f ตรงที่อาร์กิวเมนต์ที่ไม่ใช่ตัวเลือกแรกจะถือว่าเป็นสคริปต์

คุณต้องใช้inplace.awkไฟล์รวมที่รวมไว้เพื่อเรียกใช้ส่วนขยายอย่างถูกต้องดังนี้:

$ cat file
123 abc
456 def
789 hij

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

$ cat file
123
456
789

INPLACE_SUFFIXสามารถใช้ตัวแปรเพื่อระบุนามสกุลสำหรับไฟล์สำรอง:

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

$ cat file
123
456
789

$ cat file.bak
123 abc
456 def
789 hij

ผมมีความสุขคุณลักษณะนี้ได้รับการเพิ่ม แต่กับผมการดำเนินงานที่ไม่ได้เป็น awkish มากเป็นอำนาจที่มาจากความกระชับของภาษาและ-i inplaceเป็น 8 ตัวอักษรยาวเกินไปIMO

นี่คือลิงค์ไปยังคู่มือสำหรับคำทางการ


ตัวอย่าง 'แรก' ของคุณไม่ควรเป็นเช่น: awk '{ gsub(/foo/, "bar" ) } ; { print $0 }' file > tmp.txt && mv -v tmp.txt file?
Tony Barganski

ที่น่าแปลกใจของฉัน ณ เดือนเมษายน 2019 ยังคงอยู่ที่ gawk 4.0.2 อย่าให้ใครบอกคุณเช่นนั้นและเวอร์ชันดังกล่าวจะพร้อมใช้งาน
John Lunzer

น้อยกว่าawk '{print $0}' file | sponge fileโดยใช้spongeจากmoreutils.
brablc

19

แฮ็คเพียงเล็กน้อยที่ใช้งานได้

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

ใช้งานได้เหมือนมีเสน่ห์! แต่เป็นไปได้ไหมที่จะบันทึกคำสั่ง awk ลงในตัวแปรและใช้มันในเคล็ดลับดีๆของคุณ?
ashrasmun

-i inplacehardlinks วิธีการแบ่งนี้ตัดดังนี้ hardlinks ♥♥
แซนดร้า

16

@sudo_Oมีสิทธิคำตอบ

สิ่งนี้ใช้ไม่ได้:

someprocess < file > file

เชลล์ดำเนินการเปลี่ยนเส้นทางก่อนที่จะส่งการควบคุมไปยังกระบวนการบางอย่าง (การเปลี่ยนเส้นทาง ) การ>เปลี่ยนเส้นทางจะตัดทอนไฟล์ให้มีขนาดเป็นศูนย์ (การเปลี่ยนทิศทางเอาต์พุต ) ดังนั้นเมื่อถึงเวลาเปิดตัวกระบวนการและต้องการอ่านจากไฟล์จึงไม่มีข้อมูลให้อ่าน


13

อีกทางเลือกหนึ่งคือการใช้sponge:

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

ที่คุณแทนที่'{print $0}'ด้วยสคริปต์ awk ของคุณและyour_fileตามชื่อไฟล์ที่คุณต้องการแก้ไขในตำแหน่ง

sponge ดูดซับอินพุตทั้งหมดก่อนบันทึกลงในไฟล์


ฟองน้ำมาตรฐาน / พกพาได้อย่างไร?
Thomas

2
spongemoreutilsเป็นส่วนหนึ่งของ ดังนั้นจะไม่ปรากฏตามค่าเริ่มต้นในระบบส่วนใหญ่ แต่ดูเหมือนอย่างน้อยspongeตัวเองก็พกพาได้เพียงพอและสามารถใช้งานได้เกือบทุกที่
MarSoft

2
ข้อเสียของโซลูชันนี้เมื่อเทียบกับtee-based คือspongeจะอ่านทุกอย่างไปยัง RAM ก่อนที่จะเขียนลงดังนั้นมันจะหยุดบนไฟล์ขนาดใหญ่
MarSoft

6

การติดตามจะไม่ทำงาน

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

สิ่งนี้ควรใช้งานได้

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

3

ในกรณีที่คุณต้องการโซลูชัน awk อย่างเดียวโดยไม่ต้องสร้างไฟล์ชั่วคราวและใช้งานได้กับ version! = (gawk 4.1.0):

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

4
แต่สิ่งนี้จะบัฟเฟอร์ไฟล์ทั้งหมดไปยังหน่วยความจำหรือไม่? พิจารณาไฟล์ 20GB
Amit Naidu

-3

ใช้ที

 awk '{awk code}' file | tee file

teeสถานที่คำสั่งใช้และดำเนินการหลังจากที่คำสั่งเสร็จเรียบร้อยแล้วเนื่องจากการที่awk|


8
สิ่งนี้ไม่ถูกต้อง คำสั่งทั้งสองถูกดำเนินการพร้อมกันและข้อมูลจะถูกสตรีมข้ามท่อ ไฟล์ใด ๆ ที่มีขนาดใหญ่กว่าบัฟเฟอร์ (8192 ไบต์บนเครื่องของฉัน) จะถูกตัดทอนและคุณจะสูญเสียข้อมูล
tripflag
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.