Es gibt viele Möglichkeiten, Zeichen in einer Variablen zu ersetzen.
Der kürzeste Weg, den ich herausgefunden habe, ist tr
bisher:
OUTPUT=a\'b\"c\`d_123and_a_lot_more
OUTPUT=$(echo "$OUTPUT"|tr -d "'\`\"")
echo $OUTPUT
Gibt es einen schnelleren Weg? Und dann ist dies unter Angabe sicher für Angebote wie '
, "
und `selbst?
tr
. BASHs PE ist gut, aber in diesem Fall ist tr viel schneller. zBecho "$OUTPUT" | tr -dc '[[:alpha:]]'
weil Sie nur alphanumerische Zeichen haben möchtenecho "$OUTPUT"
. Oder besser:printf "%s\n" "$OUTPUT"
. (Was passiert wennOUTPUT="-n"
?)Antworten:
Wir werden sehen. Der kürzeste, den ich finden kann, ist eine Optimierung Ihrer
tr
Lösung:Andere Alternativen umfassen die bereits erwähnte Variablensubstitution, die kürzer sein kann als bisher gezeigt:
Und
sed
natürlich ist dies in Bezug auf die Charaktere länger:Ich bin mir nicht sicher, ob du die kürzeste Länge oder die kürzeste Zeit meinst. In Bezug auf die Länge sind diese beiden so kurz wie es geht (oder wie ich es sowieso bekommen kann), wenn es darum geht, diese bestimmten Zeichen zu entfernen. Welches ist das schnellste? Ich habe getestet, indem ich die
OUTPUT
Variable auf das gesetzt habe, was Sie in Ihrem Beispiel hatten, aber einige Dutzend Mal wiederholt habe:Wie Sie sehen,
tr
ist der eindeutig der Schnellste, dicht gefolgt vonsed
. Außerdem ist die Verwendung anscheinendecho
etwas schneller als die Verwendung von<<<
:Da der Unterschied winzig ist, habe ich die obigen Tests 10 Mal für jeden der beiden durchgeführt und es stellte sich heraus, dass der schnellste tatsächlich der ist, mit dem Sie beginnen mussten:
Dies ändert sich jedoch, wenn Sie den Aufwand für die Zuweisung einer Variablen berücksichtigen. Hier ist die Verwendung
tr
etwas langsamer als die einfache Ersetzung:Wenn Sie also nur die Ergebnisse anzeigen möchten, verwenden
tr
Sie , aber wenn Sie eine Variable neu zuweisen möchten, ist die Verwendung der Zeichenfolgenmanipulationsfunktionen der Shell schneller, da sie den Aufwand für die Ausführung einer separaten Subshell vermeiden.quelle
OUTPUT
, müssen Sie den Aufwand für die Befehlsersetzung in dertr
sed
OUTPUT="${OUTPUT//[`\"\']/}"
beinhaltet keine BefehlsersetzungSie können die Variablensubstitution verwenden :
Verwenden Sie diese Syntax:
${parameter//pattern/string}
um alle Vorkommen des Musters durch die Zeichenfolge zu ersetzen.quelle
echo ${OUTPUT//[`\"\']/x}
gibtaxbxcxa
In bash oder zsh ist es:
Beachten Sie, dass
${VAR//PATTERN/}
alle Instanzen des Musters entfernt werden. Weitere Informationen finden Sie in der Bash-ParametererweiterungDiese Lösung sollte für kurze Zeichenfolgen am schnellsten sein, da keine externen Programme ausgeführt werden müssen. Bei sehr langen Zeichenfolgen ist das Gegenteil der Fall - es ist besser, ein spezielles Tool für Textoperationen zu verwenden, z.
quelle
tr
ist schneller. Regexes und Globs sind teuer, und obwohl es hier kein externes Programm gibt, ist bash immer langsamer als so etwastr
.tr
gewinnt (siehe meine Antwort). Ich bin damit einverstanden, dass es von vielen Faktoren abhängt, aber genau deshalb kann man nicht sagen, welcher gewinnt, ohne ihn tatsächlich zu testen.Wenn Sie zufällig nur versuchen, Angebote für die Wiederverwendung der Shell zu verarbeiten, können Sie dies tun, ohne sie zu entfernen, und es ist auch denkbar einfach:
Diese Funktionsshell setzt ein beliebiges von Ihnen übergebenes arg-Array in Anführungszeichen und erhöht seine Ausgabe pro iterierbarem Argument.
Hier ist es mit ein paar Argumenten:
AUSGABE
Diese Ausgabe ist eine Ausgabe,
dash
die in der Regel in sicheren Anführungszeichen steht'"'"'
.bash
würde tun'\''
.Das Ersetzen einer Auswahl einzelner Bytes, die keine Leerzeichen oder Nullen enthalten, durch ein anderes Byte ist in einer POSIX-Shell mit
$IFS
und wahrscheinlich am schnellsten möglich$*
.AUSGABE
Dort habe ich es einfach
printf
so, dass man es sehen kann, aber natürlich, wenn ich es getan hätte:... und nicht der Wert des
printf
Befehls$var
, den Sie dort in der Ausgabe sehen.Wenn ich
set -f
die Shell anweise, nicht zu globieren - falls die Zeichenfolge Zeichen enthält, die als Glob-Muster ausgelegt werden könnten. Ich mache das, weil der Shells-Parser Glob-Muster erweitert, nachdem er die Feldaufteilung für Variablen durchgeführt hat. Globbing kann wie wieder aktiviert werdenset +f
. Im Allgemeinen - in Skripten - finde ich es nützlich, meinen Knall wie folgt zu setzen:Und dann explizit das Globbing mit einer
set +f
beliebigen Zeile aktivieren , die ich haben möchte.Die Feldaufteilung erfolgt anhand der Zeichen in
$IFS
.Es gibt zwei Arten von
$IFS
Werten -$IFS
Leerzeichen und$IFS
Nicht-Leerzeichen.$IFS
Durch Leerzeichen (Leerzeichen, Tabulatoren, Zeilenvorschübe) getrennte Felder werden so angegeben, dass sie nach der Reihenfolge in ein einzelnes Feld zerlegt werden (oder gar nicht, wenn sie keinem anderen Feld vorangehen) - also ...Alle anderen sind jedoch so spezifiziert, dass sie pro Vorkommen zu einem einzigen Feld ausgewertet werden - sie werden nicht abgeschnitten.
Alle Variablenerweiterungen sind standardmäßig durch
$IFS
Trennzeichen getrennte Datenfelder$IFS
. Sie werden in separate Felder aufgeteilt . Mit"
-quote one überschreiben Sie diese Array-Eigenschaft und werten sie als einzelne Zeichenfolge aus.Also, wenn ich es tue ...
Ich setze das Argumentarray der Shell auf die vielen
$IFS
begrenzten Felder, die durch$var
die Erweiterung generiert werden . Wenn es seine konstituierenden Werte für die Zeichen erweitert enthalten in$IFS
sind verloren - sie sind jetzt nur Feldtrenn - sie sind\0NUL
."$*"
- Wie bei anderen Variablenerweiterungen in doppelten Anführungszeichen - werden auch die feldaufteilenden Eigenschaften von überschrieben$IFS
. Aber zusätzlich , ersetzt es das erste Byte in$IFS
für jedes Feld begrenzt in"$@"
. Also da"
wurde der erste Wert in$IFS
allen nachfolgenden Begrenzern"
in"$*"
. Und das"
muss auch nicht sein,$IFS
wenn Sie es teilen. Sie können$IFS
afterset -- $args
vollständig auf einen anderen Wert ändern , und das neue erste Byte wird dann für die Feldbegrenzer in angezeigt"$*"
. Außerdem können Sie alle Spuren wie folgt entfernen:AUSGABE
quelle
tr
in jeder anderen Shell, aber der Unterschied ist zweifelhaftbash
für den${var//$c/$newc/}
Fall. Ich erwarte sogar in diesem Fall, dass es um einiges schneller sein wird, aber ich mache mir normalerweise keine Sorgen darüber, denn für dieses Zeug verwende ich immerdash
- was in jeder Hinsicht um Größenordnungen schneller ist. Und so ist es schwer zu vergleichen.bash
- tuntime (IFS=\"\'`; set -- $var; printf %s "$*")
undtime (var=${var//\'`/\"/})
sowohl Ergebnis in0.0000s
Ergebnissen für alle Felder. Mache ich etwas falsch, denkst du? Es sollte einen Backslash vor dem Backquote geben, aber ich weiß nicht, wie man ein Backquote in ein Kommentar-Code-Feld einfügt.