ฉันจะเปลี่ยนรหัส ^ L ในหลาย ๆ ไฟล์ใน Ubuntu ได้อย่างไร


8

ฉันมีไฟล์ XML จำนวนมากมากกว่า 50,000 ไฟล์

ในไฟล์ XML บางไฟล์ไฟล์บางไฟล์จะถูกเขียนเช่นนี้

<filename>abc.JPEG<^Lilename>

^Lเป็นเพียงตัวละครตัวหนึ่ง แต่ฉันไม่สามารถค้นหาความ^Lหมายของ Google ได้

เมื่อฉันใช้catพิมพ์เนื้อหาของไฟล์มันจะแสดงดังต่อไปนี้

<filename>abc.JPEG<
                   ilename>

อย่างไรก็ตามฉันต้องการเปลี่ยน<filename>abc.JPEG<^Lilename>เป็น<filename>abc.JPEG</filename>

ฉันพบคำสั่งบางคำเพื่อเปลี่ยนคำในไฟล์จำนวนมากเช่น

find . -exec perl -pi -e 's/[find_word]/[change_word]/g' {} \;

^Lแต่คำสั่งที่ไม่ทำงานในกรณีของฉันเพราะมันไม่สามารถรู้จักคำค้นหาเมื่อฉันเพียงแค่พิมพ์

ฉัน<filename>abc.JPEG<^Lilename>จะเปลี่ยนเป็น<filename>abc.JPEG</filename>ไฟล์จำนวนมากได้อย่างไร?


6
เห็นได้ชัดว่ามีคนใช้<\filename>แทน</filename>ในบริบทที่\fอาจตีความได้ว่าเป็นอักขระฟีดฟอร์ม คุณควรติดตามแหล่งที่มาของไฟล์เหล่านี้และชี้ให้เห็นปัญหาเกี่ยวกับเครื่องมือสร้างไฟล์ของพวกเขาให้กับนักพัฒนา สำหรับการแก้ไขไฟล์คำตอบที่ยอมรับก็ใช้ได้
Hans-Martin Mosner

คำตอบ:


17

Control-L (แสดงเป็น^L) คืออักขระ "แบบฟอร์มฟีด" ใน ASCII จะมีค่าทศนิยม 12 ( Lเป็นตัวอักษรที่ 12 ของตัวอักษร) หรือค่าฐานสิบหก 0c:

$ printf 'foo\x0cbar\n' | cat -et
foo^Lbar$

$ printf 'foo\x0cbar\n'
foo
   bar

คุณสามารถแทนที่ได้โดยใช้เครื่องมือเช่น sed โดยระบุรหัสหลบหนีฐานสิบหก:

$ printf 'foo\x0cbar\n' | sed 's/\x0c//'
foobar

เขียน^Lเรียงลำดับโดยตรงโดยใช้แป้นพิมพ์CTRL+ V CTRL+L

sed 's/CTRL+VCTRL+L//'

สำหรับการเปลี่ยนเฉพาะของคุณให้

$ printf '<\x0cilename\n'
<
 ilename

แล้วก็

$ printf '<\x0cilename\n' | sed 's/<\x0c/<\/f/g'
</filename

( gตัวดัดแปลงจะถูกเพิ่มในกรณีที่มีมากกว่าหนึ่งอินสแตนซ์ต่อบรรทัด)


ในกรณีของฉัน "$ printf '<\ x0cilename \ n' | sed 's / <\ x0c / <\\ f / g'" ไม่ทำงาน แต่ตามคำตอบของคุณ "$ find -exec perl -pi -e 's / <\ x0cilename> / <\ / filename> / g' {} \;" ทำได้ดี. ขอบคุณสำหรับคำตอบของคุณ :)
ยาง

@ ขอโทษฉันเพิ่งตระหนักว่าฉันสับสนไปข้างหน้าทับหลังและแบ็กสแลชในคำตอบของฉัน (แก้ไขตอนนี้) - ยังไม่แน่ใจว่าทำไมที่จะป้องกันไม่ให้รุ่น sed ทำงานแม้ว่า
steeldriver

คำตอบที่ดีมาก! มันจะดียิ่งขึ้นถ้ามันรวมไฟล์findที่มีลูปมากกว่าไฟล์ 50,000 ไฟล์ XML และประมวลผลแต่ละไฟล์โดยอัตโนมัติ
Kingsley

2

ตามที่ Hans-Martin Mosner ชี้ให้เห็นในความคิดเห็นดูเหมือนว่ามีคนใช้แบ็กสแลชแทนที่จะไปข้างหน้าสแลชเมื่อสร้าง XML (หรืออาจวิ่งทั่วทั้ง<filename>ส่วนผ่านตัวแปลง Unix-to-Windows ซึ่งมีปัญหาเรื่องทับ) \fเป็นลำดับ escape ที่ไม่ค่อยได้ใช้สำหรับอักขระป้อนกระดาษหรือ aka U + 0C หรือ ^ L ดังนั้นบางขั้นตอนต่อมาของไพพ์ไลน์จึงแทนที่\fด้วยอักขระ U + 0C ตามตัวอักษร

โชคดีที่ U + 0C เป็นตัวละครที่หายากมากซึ่งไม่น่าจะถูกค้นพบโดยเจตนาใน XML ประเภทใด และตั้งแต่เท่านั้น\fจะผลิตนี้เมื่อเทียบกับ (พูด) \gหรือ\kเป็นสากลค้นหาและแทนที่ควรจะแก้ไขไม่เพียง</filename>แต่ยัง</folder>, </file>หรือสิ่งอื่นที่ได้ mangled

นั่นคือสิ่งที่สคริปต์เหล็กของคนขับทำ ฉันจะทำให้มันกว้างขึ้นเล็กน้อย:

sed 's|\x0c|/f|g'

ซึ่งหมายความว่า "(s) wap ทุกกรณีของ\x0c(นั่นคือ U + 0C) ถึง/f, (g) lobally"


2

\fเป็นอักขระฟีดฟอร์มใน Perl ดูเหมือนว่าไฟล์ที่มีรูปแบบไม่ถูกต้องเหล่านี้ถูกสร้างขึ้นโดยคนใหม่สำหรับทั้ง Perl และ XML

นี่คือการแก้ไข Perlier มาก - ซึ่งยังตรงกับเป้าหมาย OP ของอัตโนมัติปรับปรุงไฟล์ทั้งหมดที่แตกต่างจากคำตอบที่ได้รับการยอมรับกับ sed findซึ่งจะทำงานเพียงหนึ่งไฟล์ในเวลาที่มันไม่ได้จับคู่กับ

\fx0cก็สามารถได้รับการว่าจ้างตัวเองแทนรหัสฐานสิบหก

find . -type f -exec perl -pi.bkp -e 's [ \f ilename ][ /f ilename ]gx' {} \;

ที่นี่ฉันได้เพิ่ม-type fโทรfindเข้าเพื่อส่งคืนไฟล์ธรรมดา - มิฉะนั้นfindจะส่งคืน.ในรายการและเรียกใช้คำเตือนเมื่อคุณพยายามแก้ไข แต่ทุกอย่างจะยังคงใช้งานได้

ฉันยังทำให้การมองเห็น regex ง่ายขึ้นโดยใช้xแฟล็กซึ่งไม่สนใจช่องว่างที่แท้จริงช่วยให้คุณสามารถเว้นองค์ประกอบของ regex ของคุณ หากคุณไม่ชอบสิ่งนี้แสดงว่าไม่มี:

find . -type f -exec perl -pi.bkp -e 's[\filename][/filename]g' {} \;

และในกรณีที่เป็นไปได้ว่าตัวอักขระฟีดแบบฟอร์มทั้งหมดจะถูกปลอมและควรแทนที่ด้วยทั้งหมดจาก/fนั้นคุณสามารถเพรียวบางซับลงได้อีก:

find . -type f -exec perl -pi.bkp -e 's[\f][/f]g' {} \;

คุณไม่จำเป็นต้องใช้เครื่องหมายทับซ้ายเพื่อล้อมองค์ประกอบของคำสั่งการแทนที่ regex ( s///) ใน Perl คุณสามารถใช้สัญลักษณ์ใด ๆ หากคุณเลือกใช้สัญลักษณ์คล้ายวงเล็บคู่ใด ๆ คุณต้องใช้ทั้งสองอย่างs[old][new]เช่น

เนื่องจากฉันไม่ได้ใช้สแลชฉันจึงไม่ต้องหนีเครื่องหมายสแลชใด ๆ

สำหรับ-i.bkp: perl -pi -eช่วยให้คุณแก้ไขในสถานที่ - แต่ถ้าคุณต้องการประกันเพิ่มเติมในกรณีที่คุณพบโปรแกรม Perl ที่ค้นหาและแทนที่ไม่ถูกต้องคุณสามารถใส่นามสกุลไฟล์เพื่อที่จะทำสำเนาไฟล์ต้นฉบับสำหรับ คุณ. .bkpที่นี่ผมเคยใช้

ใน Perl เวอร์ชั่นล่าสุดการแก้ไขในสถานที่ได้รับการปรับปรุงให้มีความยืดหยุ่นมากขึ้นในกรณีที่ระบบของคุณประสบปัญหาร้ายแรงเช่นการสูญเสียพลังงานหรือการใช้พื้นที่ดิสก์ไม่เพียงพอ ที่นี่ผู้เขียน Perl คือไบรอัน d foy ในการปรับปรุงแก้ไขในสถาน Perls ล่าสุด

คุณควรพิจารณาใช้ Perl สำหรับงานประเภทนี้เพราะเป็นภาษาการเขียนโปรแกรมที่มีประสิทธิภาพสูง แต่ไม่ได้มาตรฐานอันดับหนึ่งซึ่งมีเป้าหมายการออกแบบดั้งเดิมคือการแทนที่sedและแทนที่awkด้วยสิ่งที่ดีกว่ามาก

Perl 5 ความสามารถในการจับคู่ regex และไวยากรณ์ regex ดีขึ้นไกลเกินเหล่านั้นsed, awkและแน่นอนทุกภาษาโปรแกรมอื่น ๆ นอกเหนือจาก Perl 6 ทำให้ Perl เป็นทางเลือกที่เหมาะสมที่สุดสำหรับทั้งง่ายและกิจวัตร regex ขั้นสูง

ชี้แจง: sedจะทำงานด้วยfindและคุณยังสามารถใช้sed -i.bkpในการสำรองข้อมูลของแต่ละไฟล์ที่แก้ไข แต่เท่าที่ฉันรู้ว่ามันไม่ได้มีความยืดหยุ่นพิเศษใน Perl 5.28 ขึ้นไป นอกจากนี้ยังใช้ clunkier และไวยากรณ์ UNIX ®แบบดั้งเดิมที่มีประสิทธิภาพน้อยกว่ามาก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.