คำตอบที่ง่ายที่สุดและพกพามากที่สุดคือเรียกใช้สิ่งนี้:
#!/usr/bin/env perl
use strict;
use warnings;
use File::Find;
my @dirs = (@ARGV == 0) ? <*> : @ARGV;
find sub {
next unless -f && -T;
system('perl', '-i', '-pe', 's/[\t\xA0 ]+$//', $File::Find::name);
} => @dirs;
ฉันอธิบายว่าทำไมด้านล่างซึ่งฉันยังแสดงให้เห็นถึงวิธีการใช้เพียงบรรทัดคำสั่งเช่นเดียวกับวิธีจัดการกับไฟล์ข้อความ trans-ASCII เช่น ISO-8859-1 (ละติน -1) และ UTF-8 ซึ่งไม่ได้ผล -ASCII ช่องว่างในพวกเขา
ส่วนที่เหลือของเรื่อง
ปัญหาคือการหา (1) ไม่รองรับ-T
ผู้ประกอบการทดสอบไฟล์และไม่รู้จักการเข้ารหัสถ้ามัน - ซึ่งคุณจำเป็นต้องตรวจสอบ UTF-8, การเข้ารหัส Unicode มาตรฐานโดยพฤตินัย
สิ่งที่คุณสามารถทำได้คือเรียกใช้รายชื่อไฟล์ผ่านเลเยอร์ที่ส่งออกไบนารีไฟล์ ตัวอย่างเช่น
$ find . -type f | perl -nle 'print if -T' | xargs sed -i 's/[ \t]*$//'
อย่างไรก็ตามตอนนี้คุณมีปัญหากับช่องว่างในชื่อไฟล์ของคุณดังนั้นคุณต้องมาช้ากว่านี้ด้วยการยกเลิกแบบ null:
$ find . -type f -print0 | perl -0 -nle 'print if -T' | xargs -0 sed -i 's/[ \t]*$//'
สิ่งอื่นที่คุณสามารถทำได้คือไม่ใช้find
แต่find2perl
เนื่องจาก Perl เข้าใจ-T
แล้ว:
$ find2perl * -type T -exec sed 's/[ \t]*$//' -i {} \; | perl
และถ้าคุณต้องการให้ Perl ถือว่าไฟล์อยู่ใน UTF-8 ให้ใช้
$ find2perl * -type T -exec sed 's/[ \t]*$//' -i {} \; | perl -CSD
หรือคุณสามารถบันทึกสคริปต์ที่ได้ในไฟล์และแก้ไขมัน คุณไม่ควรเรียกใช้ไฟล์-T
ทดสอบในไฟล์เก่า แต่ควรใช้เฉพาะไฟล์ที่เป็นไฟล์ธรรมดาตามที่พิจารณา-f
ก่อน มิฉะนั้นคุณจะเสี่ยงต่อการเปิดอุปกรณ์พิเศษปิดกั้นฟีด ฯลฯ
แต่ถ้าคุณจะทำทุกสิ่งที่คุณอาจรวมทั้งข้ามsed (1) โดยสิ้นเชิง สำหรับสิ่งหนึ่งมันพกพาได้มากกว่าเนื่องจากรุ่น POSIX ของsed (1) ไม่เข้าใจ-i
ในขณะที่ Perl ทุกรุ่นทำ รุ่นที่ผ่านมาของsed ได้รับการจัดสรรด้วยความรักเป็น-i
ตัวเลือกที่มีประโยชน์มากจาก Perl ซึ่งจะปรากฏขึ้นเป็นครั้งแรก
สิ่งนี้ยังให้โอกาสคุณในการแก้ไข regex ของคุณอีกด้วย คุณควรใช้รูปแบบที่ตรงกับช่องว่างแนวนอนหนึ่งช่องหรือมากกว่านั้นไม่ใช่แค่ศูนย์หรือคุณจะทำงานช้าลงจากการทำสำเนาที่ไม่จำเป็น นั่นคือสิ่งนี้:
s/[ \t]*$//
ควรจะเป็น
s/[ \t]+$//
อย่างไรก็ตามวิธีที่จะทำให้sed (1) เข้าใจว่าต้องใช้ส่วนขยายที่ไม่ใช่ POSIX โดยทั่วไป-R
สำหรับระบบ System Unices เช่น Solaris หรือ Linux หรือ-E
BSD เช่น OpenBSD หรือ MacOS ฉันสงสัยว่ามันเป็นไปไม่ได้ภายใต้ AIX การเขียนเชลล์แบบพกพานั้นง่ายกว่าการใช้เชลล์สคริปต์แบบพกพา
เตือนเมื่อ 0xA0
แม้ว่าจะเป็นอักขระช่องว่างแนวนอนเท่านั้นใน ASCII ทั้ง ISO-8859-1 และดังนั้น Unicode จึงมี NO-BREAK SPACE ที่จุดโค้ด U + 00A0 นี่เป็นหนึ่งในสองอักขระที่ไม่ใช่ ASCII อันดับแรกที่พบใน Unicode corpora หลายแห่งและฉันได้เห็นการแตกรหัส regex ของผู้คนจำนวนมากเมื่อเร็ว ๆ นี้เพราะพวกเขาลืมมันไป
ดังนั้นทำไมคุณไม่ทำเช่นนี้:
$ find * -print0 | perl -0 -nle 'print if -f && -T' | xargs -0 perl -i -pe 's/[\t\xA0 ]+$//'
ถ้าคุณอาจมี UTF-8 ไฟล์ที่จะจัดการกับการเพิ่ม-CSD
และถ้าคุณกำลังเรียกใช้ Perl V5.10 หรือสูงกว่าคุณสามารถใช้\h
สำหรับช่องว่างในแนวนอนและ\R
สำหรับ LINEBREAK ทั่วไปซึ่งรวมถึง\r
, \n
, \r\n
, \f
, \cK
, \x{2028}
และ\x{2029}
:
$ find * -print0 | perl -0 -nle 'print if -f && -T' | xargs -0 perl -CSD -i -pe 's/\h+(?=\R*$)//'
ที่จะทำงานกับไฟล์ UTF-8 ทั้งหมดไม่ว่าจะมีการแพร่กระจายของพวกมันกำจัดช่องว่างในแนวนอน (คุณสมบัติอักขระ Unicode HorizSpace
) รวมถึงช่องว่างNO-BREAK ที่น่ารำคาญที่เกิดขึ้นก่อน Unicode Linebreak (รวมคอมโบ CRLF) ในตอนท้ายของแต่ละบรรทัด
นอกจากนี้ยังพกพาได้มากกว่ารุ่นsed (1) มากเนื่องจากมีการติดตั้งPerlเพียงครั้งเดียว(1) แต่มีsed (1) จำนวนมาก
ปัญหาหลักที่ฉันเห็นมีอยู่คือfind (1) เนื่องจากในระบบ recalcitrant บางระบบ (คุณรู้ว่าคุณคือใคร AIX และ Solaris) มันจะไม่เข้าใจ-print0
คำสั่งsupercritical หากนั่นคือสถานการณ์ของคุณคุณควรใช้File::Find
โมดูลจาก Perl โดยตรงและไม่ต้องใช้ยูทิลิตี้ Unix อื่น ๆ นี่เป็นโค้ด Perl ของคุณบริสุทธิ์ที่ไม่ต้องพึ่งพาสิ่งอื่นใด:
#!/usr/bin/env perl
use strict;
use warnings;
use File::Find;
my @dirs = (@ARGV == 0) ? <*> : @ARGV;
find sub {
next unless -f && -T;
system('perl', '-i', '-pe', 's/[\t\xA0 ]+$//', $File::Find::name);
} => @dirs;
หากคุณใช้ไฟล์ข้อความเพียง ASCII หรือ ISO-8859-1 ก็ถือว่าใช้ได้ แต่ถ้าคุณใช้ไฟล์ ASCII หรือ UTF-8 ให้เพิ่ม-CSD
สวิตช์ในการโทรภายในไปยัง Perl
หากคุณมีการเข้ารหัสแบบผสมทั้งสามของ ASCII, ISO-8859-1 และ UTF-8 ฉันกลัวว่าคุณจะมีปัญหาอื่น :( คุณจะต้องคิดการเข้ารหัสแบบต่อไฟล์และไม่มีวิธีที่ดีที่จะเดาได้
ช่องว่าง Unicode
สำหรับเร็กคอร์ด Unicode มีอักขระช่องว่าง 26 ตัวที่แตกต่างกัน คุณสามารถใช้unicharsยูทิลิตี้เพื่อสูดอากาศออกเหล่านี้ เฉพาะช่องว่างแนวนอนสามช่องแรกเท่านั้นที่จะเห็น:
$ unichars '\h'
---- U+0009 CHARACTER TABULATION
---- U+0020 SPACE
---- U+00A0 NO-BREAK SPACE
---- U+1680 OGHAM SPACE MARK
---- U+180E MONGOLIAN VOWEL SEPARATOR
---- U+2000 EN QUAD
---- U+2001 EM QUAD
---- U+2002 EN SPACE
---- U+2003 EM SPACE
---- U+2004 THREE-PER-EM SPACE
---- U+2005 FOUR-PER-EM SPACE
---- U+2006 SIX-PER-EM SPACE
---- U+2007 FIGURE SPACE
---- U+2008 PUNCTUATION SPACE
---- U+2009 THIN SPACE
---- U+200A HAIR SPACE
---- U+202F NARROW NO-BREAK SPACE
---- U+205F MEDIUM MATHEMATICAL SPACE
---- U+3000 IDEOGRAPHIC SPACE
$ unichars '\v'
---- U+000A LINE FEED (LF)
---- U+000B LINE TABULATION
---- U+000C FORM FEED (FF)
---- U+000D CARRIAGE RETURN (CR)
---- U+0085 NEXT LINE (NEL)
---- U+2028 LINE SEPARATOR
---- U+2029 PARAGRAPH SEPARATOR