Die einfachste und portabelste Antwort lautet:
#!/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;
Ich erkläre unten, warum, wo ich auch zeige, wie man es nur mit der Befehlszeile macht, und wie man mit trans-ASCII-Textdateien wie ISO-8859-1 (Latin-1) und UTF-8 umgeht, die oft keine haben -ASCII Leerzeichen in ihnen.
Der Rest der Geschichte
Das Problem ist, dass find (1) weder den -T
Dateitest-Operator unterstützt, noch Codierungen erkennt, wenn dies der Fall ist - was unbedingt erforderlich ist, um die UTF-8-Standard-Unicode-Codierung zu erkennen.
Sie könnten die Dateinamenliste durch eine Ebene führen, die Binärdateien ausgibt. Zum Beispiel
$ find . -type f | perl -nle 'print if -T' | xargs sed -i 's/[ \t]*$//'
Jetzt haben Sie jedoch Probleme mit Leerzeichen in Ihren Dateinamen. Daher müssen Sie dies mit Nullterminierung verspäten:
$ find . -type f -print0 | perl -0 -nle 'print if -T' | xargs -0 sed -i 's/[ \t]*$//'
Eine andere Sache, die Sie tun könnten, ist nicht zu verwenden, find
aber find2perl
, da Perl -T
bereits versteht :
$ find2perl * -type T -exec sed 's/[ \t]*$//' -i {} \; | perl
Und wenn Sie möchten, dass Perl davon ausgeht, dass sich die Dateien in UTF-8 befinden, verwenden Sie
$ find2perl * -type T -exec sed 's/[ \t]*$//' -i {} \; | perl -CSD
Sie können das resultierende Skript auch in einer Datei speichern und bearbeiten. Sie sollten wirklich wirklich nicht nur den -T
Filetest auf einer alten Datei ausführen, sondern nur auf Dateien, die reine Dateien sind, wie zuerst von bestimmt -f
. Andernfalls riskieren Sie das Öffnen von Gerätespecials, das Blockieren von Fifos usw.
Wenn Sie dies jedoch alles tun, können Sie sed (1) genauso gut überspringen . Zum einen ist es portabler, da die POSIX-Version von sed (1) dies nicht versteht -i
, wohingegen alle Versionen von Perl dies tun. Die neueren Versionen von sed haben die sehr nützliche -i
Option von Perl liebevoll übernommen, bei der ti zum ersten Mal auftaucht.
Dies gibt Ihnen auch die Möglichkeit, Ihren regulären Ausdruck zu korrigieren. Sie sollten wirklich ein Muster verwenden, das mit einem oder mehreren horizontalen Leerzeichen übereinstimmt, und nicht mit Null, da sonst unnötige Kopiervorgänge langsamer ablaufen. Dies ist das:
s/[ \t]*$//
sollte sein
s/[ \t]+$//
Um sed (1) zu verstehen, ist jedoch eine Nicht-POSIX-Erweiterung erforderlich, normalerweise entweder -R
für System Ⅴ Unices wie Solaris oder Linux oder -E
für BSD wie OpenBSD oder MacOS. Ich vermute, dass es unter AIX unmöglich ist. Es ist leider einfacher, eine tragbare Shell zu schreiben als ein Skript für eine tragbare Shell, wissen Sie.
Warnung an 0xA0
Obwohl dies die einzigen horizontalen Leerzeichen in ASCII sind, haben sowohl ISO-8859-1 als auch Unicode das Leerzeichen NO-BREAK am Codepunkt U + 00A0. Dies ist eines der beiden wichtigsten Nicht-ASCII-Zeichen, die in vielen Unicode-Corpora vorkommen, und ich habe in letzter Zeit viele Leute gesehen, die den regulären Code gebrochen haben, weil sie ihn vergessen haben.
Warum machst du das nicht einfach so:
$ find * -print0 | perl -0 -nle 'print if -f && -T' | xargs -0 perl -i -pe 's/[\t\xA0 ]+$//'
Wenn Sie könnten UTF-8 - Dateien zu behandeln, hinzufügen -CSD
, und wenn Sie Perl v5.10 oder höher ausgeführt wird , können Sie \h
für die horizontalen Leerzeichen und \R
für einen generischen Zeilenumbrüche, die beinhalten \r
, \n
, \r\n
, \f
, \cK
, \x{2028}
, und \x{2029}
:
$ find * -print0 | perl -0 -nle 'print if -f && -T' | xargs -0 perl -CSD -i -pe 's/\h+(?=\R*$)//'
Dies funktioniert für alle UTF-8-Dateien, unabhängig von den Zeilenumbrüchen, und beseitigt nachfolgende horizontale Leerzeichen (Unicode-Zeicheneigenschaft HorizSpace
), einschließlich des lästigen Leerzeichens NO-BREAK, das vor einem Unicode-Zeilenumbruch (einschließlich CRLF-Combos) am Ende jeder Zeile auftritt.
Es ist auch viel portabler als die sed (1) -Version, da es nur eine Perl (1) -Implementierung gibt, aber viele sed (1).
Das Hauptproblem, von dem ich sehe, dass es dort verbleibt, ist find (1), da es auf einigen wirklich widersprüchlichen Systemen (Sie wissen, wer Sie sind, AIX und Solaris) die überkritische -print0
Direktive nicht versteht . Wenn das Ihre Situation ist, sollten Sie einfach das File::Find
Modul von Perl direkt verwenden und keine anderen Unix-Dienstprogramme verwenden. Hier ist eine reine Perl-Version Ihres Codes, die sich auf nichts anderes stützt:
#!/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;
Wenn Sie nur ASCII- oder ISO-8859-1-Textdateien verwenden, ist dies in Ordnung. Wenn Sie jedoch ASCII- oder UTF-8-Dateien verwenden, fügen Sie die Optionen im internen -CSD
Aufruf von Perl hinzu.
Wenn Sie alle drei Codierungen von ASCII, ISO-8859-1 und UTF-8 gemischt haben, dann befürchte ich, dass Sie ein anderes Problem haben. :( Sie müssen die Kodierung auf Dateibasis herausfinden, und es gibt nie einen guten Weg, das zu erraten.
Unicode-Leerzeichen
Für den Datensatz hat Unicode 26 verschiedene Whitespace-Zeichen. Sie können das Dienstprogramm unichars verwenden, um diese auszuspionieren . Es werden fast immer nur die ersten drei horizontalen Whitespace-Zeichen angezeigt:
$ 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