
Ich verwende derzeit folgendesvereinfachter BefehlZunachstehende Leerzeichen entfernenUndfüge am Ende der Datei eine neue Zeile hinzuwo benötigt:
find . -type f -exec sed -i -e 's/[ \t]\+\(\r\?\)$/\1/;$a\' {} \+
Wie Sie schnell sehen werden, gibt es dabei zwei Probleme: Es wird sich ändernBinärdateienund es wird eine neue Zeile am Ende der Dateien hinzugefügt mit␍␊ Zeilentrennzeichen. Diese Änderungen können beim Commiten git gui
oder Ähnlichem leicht rückgängig gemacht oder übersprungen werden, aber ich möchte die Anzahl der Rückgängigmachungen minimieren*. Zu diesem Zweck:
Gibt es eine Möglichkeit, das zu überspringen?ganzDatei, wennbeliebigZeile entspricht einem regulären Ausdruck in sed
?
* Mir ist bewusst, dass es Binärdateien ohne ␀-Zeichen geben könnte und dass es Dateien mit absichtlich gemischten Zeilenumbrüchen oder ␀s geben könnte. Aber ich suche nach einer Lösung, die das minimale menschliche Eingreifen erfordert. IchkönnteEs wäre denkbar, alle Dateierweiterungen aufzulisten, die ich bearbeiten möchte, aber es wäre eine sehr lange Liste, die ständig überprüft werden müsste, und aufgrund von Namenskonflikten wäre es immer noch möglich, dass Binärdateien durchrutschen.
KompliziertProblemumgehung:
while IFS= read -r -d '' -u 9
do
if [[ "$(file -bs --mime-type -- "$REPLY")" = text/* ]]
then
sed -i -e 's/[ \t]\+\(\r\?\)$/\1/;$a\' -- "$REPLY"
else
echo "Skipping $REPLY" >&2
fi
done 9< <(find . -type f -print0)
Antwort1
Wenn Sie git
der Ansicht von vertrauen, was eine Binärdatei ist und was nicht, können Sie git grep
eine Liste nichtbinärer Dateien abrufen. Angenommen, es t.cpp
handelt sich um eine Textdatei und ls
eine Binärdatei, sind beide eingecheckt:
$ ls
t.cpp ls
$ git grep -I --name-only -e ''
t.cpp
Die -I
Option bedeutet:
-I
Passen Sie das Muster nicht in Binärdateien an.
So kombinieren Sie das mit Ihrem sed
Ausdruck:
$ git grep -I --name-only -z -e '' | \
xargs -0 sed -i.bk -e 's/[ \t]\+\(\r\?\)$/\1/;$a\'
( -z
/ xargs -0
als Hilfe bei seltsamen Dateinamen.)
Weitere nützliche Optionen finden Sie auf der git grep
Manpage. --no-index
Diese --cached
könnten hilfreich sein, je nachdem, welchen Dateisatz Sie genau bearbeiten möchten.
Antwort2
Gibt es eine Möglichkeit, die gesamte Datei zu überspringen, wenn eine beliebige Zeile mit einem regulären Ausdruck in sed übereinstimmt?
Ja da ist.
# test case for skipping file if a sed regex match succeeds
echo 'Hello, world!' > hello_world.txt
cat hello_world.txt
ls -li hello_world.txt
sed -i -e '/.*Hello.*/{q;}; s/world/WORLD/g' hello_world.txt # skips file
sed -i -e '/.*HeLLo.*/{q;}; s/world/WORLD/g' hello_world.txt
Antwort3
Hier ist ein Perl-Skript, das seine Argumente (die Dateinamen sein müssen) durchläuft und an jede Datei, die nicht mit einer neuen Zeile endet, eine neue Zeile anfügt. Dateien, die ein Nullbyte enthalten, werden übersprungen. Dateien, die bereits mit einer neuen Zeile enden, bleiben unverändert. An Dateien, die ein CR enthalten, wird CRLF angehängt, an andere nur LF. Ungetestet.
#!/usr/bin/env perl
foreach my $f (@ARGV) {
open F, "<", $f or die;
my $last = undef;
my $cr = 0;
while (<>) {if (/\0/) {undef $last; break} $last = $_; ++$cr if /\r$/}
close F;
if (defined $last && $last !~ /\n\Z/) {
open F, ">>", $f or die;
print($cr ? "\r\n" : "\n");
close F or die;
}
}