Entfernen Sie nachstehende Leerzeichen NUR, wenn nötig, aus Textdateien

Entfernen Sie nachstehende Leerzeichen NUR, wenn nötig, aus Textdateien

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 grepfirst 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/sedwie 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, grepund \;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 , sedanstatt nur die einzelnen Dateien {}des aktuellen Ergebnisses zu übergeben). Dadurch können wir die Anzahl der Aufrufe minimieren .find{}sedsed

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 sedAufrufen 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

verwandte Informationen