Wie entferne ich mehrere Sonderzeichen aus einer Datei?

Wie entferne ich mehrere Sonderzeichen aus einer Datei?

Das folgende Skript entfernt derzeit das Zeichen ^M ( Ctrl+V+M). Ich finde es etwas langatmig, aber ich muss auch ^I und alle anderen Zeichen hinzufügen, die ich in Zukunft sehen könnte.

Gibt es eine einfachere Möglichkeit, ^I ( ) hinzuzufügen Ctrl+V+I? Dies ist das erste Skript, das ich vor etwa 6 Monaten für mich selbst geschrieben habe, nachdem ich einen zweitägigen Shell-Programmierkurs besucht hatte. Ich bin mir nicht sicher, ob ich es länger gemacht habe als nötig, daher wären auch allgemeine Tipps willkommen.

#!/bin/bash  

    echo "$# item(s) to review."
    question='Do you want to remove the ^M characters?'

    for file
    do
            if grep "^M" "$file" >> /dev/null 2> /dev/null
            then
                    echo "$file contains special characters"
                    echo $question
                    read answer
                            if    [[ "$answer" == [yY] ]]
                            then
                                    cat "$file" | sed "s/^M//" > "$file.safe"
                                    echo "Special characters have been removed and $file.safe has been created."
                            elif  [[ "$answer" == [yY][eE][sSaA]* ]]
                            then
                                    cat "$file" | sed "s/^M//" > "$file.safe"
                                    echo "Special characters have been removed and $file.safe has been created."
                            else
                                    echo "Special characters have NOT been removed."
                            fi
            elif [[ -d $file ]]
            then
                    echo "$file is a directory"
            else
                    echo "No special characters in $file"
            fi
    done

Antwort1

Das ist sicherlich viel, viel länger als nötig. Alles was Sie brauchen ist dietrDienstprogramm, plus eine Schleife und Umleitungen, um auf die Dateien einzuwirken, die als Argumente an das Skript übergeben werden.

#!/bin/sh
for file do
  tr -d '\r\t' <"$file" >"$file.safe"
done

Mit der Option -dwerden trdie angegebenen Zeichen entfernt. Die zu entfernenden Zeichen werden zusammen als erstes Argument ohne Option übergeben. Sie können Backslash-Escapes verwenden, um Sonderzeichen darzustellen: \nfür eine neue Zeile (^J), \rfür einen Wagenrücklauf (^M), \tfür einen Tabulator (^I) usw.

Ich habe den Code zum Abfragen an den Benutzer nicht reproduziert, da er sinnlos ist. Verzeichnisse verursachen bei der Umleitung sowieso einen Fehler, und es ist eigentlich die Aufgabe des Anrufers, keine unsinnige Aktion wie die Behandlung eines Verzeichnisses als normale Datei anzufordern, daher habe ich diesen Teil auch übersprungen.

Wenn Sie die Originaldatei ersetzen möchten, schreiben Sie in eine temporäre Datei und verschieben Sie das Ergebnis an die gleiche Stelle.

#!/bin/sh
for file do
  tmp="$(TMPDIR=$(dirname -- "$file") mktemp)"
  tr -d '\r\t' <"$file" >"$tmp" && mv -f -- "$tmp" "$file"
done

Der temporäre Dateiname wird mit erstellt, mktempdamit das Skript robust ist. Es funktioniert, solange Sie Schreibberechtigung für das Verzeichnis haben, das die Datei enthält, ohne das Risiko einzugehen, eine vorhandene Datei zu überschreiben. Es ist sicher, selbst wenn das Verzeichnis von anderen Benutzern beschreibbar ist, die versuchen könnten, andere Daten einzuschleusen (ein potenzielles Problem in /tmp).

Der mvBefehl wird nur aufgerufen, wenn der Aufruf trerfolgreich war. Es besteht daher keine Gefahr, dass Daten verloren gehen, wenn der Aufruf trfehlschlägt, z. B. weil die Festplatte während des Aufrufs voll wird.

Wenn Sie das Ersetzen der Datei durch eine neue, identische Datei vermeiden möchten, sofern diese keine Sonderzeichen enthält, gibt es zwei Möglichkeiten:

  • Sie können zuerst nach Sonderzeichen suchen. Dafür gibt es mehrere Möglichkeiten. Eine Möglichkeit besteht darin, alles außer diesen Sonderzeichen zu entfernen und die Anzahl der resultierenden Zeichen zu zählen. Zur Optimierung können Sie eine Weiterleitung durchführen, head -c 1sodass Sie nicht die gesamte Datei durchsuchen müssen, wenn ein Sonderzeichen ganz oben gefunden wird: Auf diese Weise ist die Anzahl 0, wenn nichts zu tun ist, und 1, wenn nicht.

    if [ "$(tr -dc '\r\t' <"$file" | head -c 1 | wc -c)" -ne 0 ]; then
      tr -d '\r\t' <"$file" >"$tmp" && mv -f -- "$tmp" "$file"
    fi
    
  • Sie können die Transformation durchführen und dann prüfen, ob sie mit dem Original identisch ist. Dies kann langsamer sein, wenn die Dateien häufig bereits im gewünschten Zustand sind. Andererseits lässt sich diese Technik auf Fälle verallgemeinern, in denen es nicht einfach ist, festzustellen, ob die Datei im gewünschten Zustand ist.

    tr -d '\r\t' <"$file" >"$tmp" &&
    if cmp -s "$tmp" "$file"; then
      rm -- "$tmp"
    else
      mv -f -- "$tmp" "$file"
    fi
    

Antwort2

Sie können eine Schleife um Ihr Skript legen. Also:

 for c in "^I" "^M"; do
    for file; do
       if grep "$c" "$file"; then
          ...
          etc.
          ...
       fi
    done
 done

Antwort3

Ich bevorzuge diesen Perl-Einzeiler. Das '\cM' ist das Strg-M-Zeichen. Die Originaldatei(en) werden mit der Erweiterung '.bak' gesichert. Diese Erweiterung können Sie frei wählen.

perl -i.bak -pe 's/\cM//g;'  file(s)

Beispiel für die Verwendung einer Klasse von zu entfernenden Zeichen. In den Klammern findet Perl Strg-I und Strg-M und entfernt sie. Ich habe das allerdings nicht genau getestet.

perl -i.bak -pe 's/[\cM\cI]//g;' files(s)

Antwort4

Haben Sie daran gedacht,

 tr -d .....<characterlist>....

Entfernen Sie beispielsweise alle nicht druckbaren Zeichen und fügen Sie sie in eine andere Datei ein:

 cat filename | tr -cd '[:print:]' >/tmp/x.out

Passen Sie die Zeichenliste Ihrer Anwendung an. trWeitere Informationen finden Sie auf der Manpage.

Außerdem ist es schön, weil Regex-Bereiche zulässig sind:

 echo '\001\002\003\004' | tr -d '[\001-\003]' | od -c

verwandte Informationen