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 dietr
Dienstprogramm, 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 -d
werden tr
die angegebenen Zeichen entfernt. Die zu entfernenden Zeichen werden zusammen als erstes Argument ohne Option übergeben. Sie können Backslash-Escapes verwenden, um Sonderzeichen darzustellen: \n
für eine neue Zeile (^J), \r
für einen Wagenrücklauf (^M), \t
fü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, mktemp
damit 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 mv
Befehl wird nur aufgerufen, wenn der Aufruf tr
erfolgreich war. Es besteht daher keine Gefahr, dass Daten verloren gehen, wenn der Aufruf tr
fehlschlä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 1
sodass 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. tr
Weitere 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