Ich entferne die nachstehenden Leerzeichen mit
sed -i 's/[ \t]*$//' *.txt
Dieser Befehl schreibt jedoch alle Dateien neu.
Gibt es eine einfache Möglichkeit, festzustellen, ob eine Textdatei nachstehende Leerzeichen enthält, und die Dateien ohne nachstehende Leerzeichen zu überspringen?
Antwort1
Sie könnten grep
first verwenden, um herauszufinden, ob Zeilen vorhanden sind, die geändert werden müssen. Dadurch würden die Dateien jedoch im schlimmsten Fall trotzdem zweimal gelesen (wenn nur die letzte Zeile geändert werden muss):
for f in ./*.txt; do
grep -q '[[:blank:]]$' "$f" &&
sed -i 's/[[:blank:]]*$//' "$f"
done
Antwort2
Eine Möglichkeit hierzu kann find/grep/sed
wie folgt aussehen:
find . -maxdepth 1 -type f -name '*.txt' \
-exec grep -q '[[:blank:]]$' {} \; \
-exec sed -Ei -e 's/[[:blank:]]+$//' {} +
- Die Suche mit -maxdepth wenn 1 erfolgt innerhalb des aktuellen Verzeichnisses.
{} \;
bezieht sich auf den Namen der Datei, an die übergeben wird,grep
und\;
maskiert das Shell-Metazeichen Semikolon, das ein Indikator für das Ende des Befehls ist. Wir maskieren es, damit es erreicht-exec
. Sie hätten es alternativ auch so schreiben können:';'
{} +
Sie wissen es bereits{}
und das+
bedeutet, dass Sie so viele Dateinamen wie möglich übergeben (im Grunde genommen erstellen Sie eine Liste von Dateien, die als Argument verwendet werden, bevor Sie aufrufen ,sed
anstatt nur die einzelnen Dateien{}
des aktuellen Ergebnisses zu übergeben). Dadurch können wir die Anzahl der Aufrufe minimieren .find
{}
sed
sed
Antwort3
Führen Sie die Bearbeitung durch und ersetzen Sie die Originaldatei nur, wenn ein Unterschied besteht.
for file in *.txt
do
sed 's/[ \t]*$//' < "$file" > "$file.tmp.$$" || continue
cmp -s -- "$file" "$file.tmp.$$" ||
cat < "$file.tmp.$$" > "$file" ||
continue
rm -f -- "$file.tmp.$$"
done
Antwort4
Das Folgende baut aufroaimas Ideeden Ausdruck für alle Dateien auszuführen sed
, dann aber nur die Dateien beizubehalten, die tatsächlich geändert wurden.
Dies wird durch die Durchführung von weniger sed
Aufrufen geändert:
printf '%s\0' ./*.txt |
xargs -0 sed -i.bak 's/[[:blank:]]$//
Anschließend können Sie die Dateien durchgehen *.txt
, sie mit den Originalen vergleichen und die Datei auswählen, die Sie behalten möchten:
for name in ./*.txt; do
if cmp -s "$name" "$name.bak"; then
# keep original
mv "$name.bak" "$name"
else
# keep modified
rm "$name.bak"
fi
done
Oder beides auf einmal:
printf '%s\0' ./*.txt |
xargs -0 sh -c '
sed -i.bak "s/[[:blank:]]$//" "$@"
for name do
if cmp -s "$name" "$name.bak"; then
mv "$name.bak" "$name"
else
rm "$name.bak"
fi
done' sh