Manipulation von Piping-Bash-Strings

9

Ich habe einige andere Fragen zur Manipulation von Piping-Bash-Strings gelesen, aber es scheint sich um spezielle Anwendungen zu handeln.

Gibt es im Wesentlichen eine Möglichkeit, das Folgende einfacher zu machen?

anstatt

$ string='hello world'; string2="${string// /_}"; echo "${string2^^}"
HELLO_WORLD

etwas wie

$ echo 'hello world' | $"{-// /_}" | "${ -^^}"
HELLO_WORLD

Bearbeiten Ich bin daran interessiert, wenn möglich innerhalb von Bash-Manipulationen zu bleiben, um die Geschwindigkeit aufrechtzuerhalten (im Gegensatz zu sed / awk, die dazu neigen, meine Skripte stark zu verlangsamen).

Edit2: @jimmij

Ich mag das zweite Beispiel und habe mich dazu gebracht, eine Funktion zu machen.

bash_m() { { read x; echo "${x// /_}"; } | { read x; echo "${x^^}"; }; }
echo hello world | bash_m
HELLO_WORLD
Miati
quelle
1
Warum denkst du, wäre sed / awk für diesen Zweck langsam? Sie sind so schnell wie sie kommen.
mkc
1
@Ketan Sed und awk sind separate Prozesse, daher können sie niemals so schnell sein, wie es Bash nativ kann, ohne einen separaten Prozess zu starten. Normalerweise ist dieser Unterschied kaum spürbar, aber wenn die Leistung in Shell-Skripten von Bedeutung ist, wird normalerweise eine bestimmte Schleife oder Berechnung sehr oft wiederholt, und das Laichen von Tausenden von Prozessen ist merklich langsamer als eine einfache String-Manipulation in Bash nativ.
jw013
2
@ jw013 Dies gilt für kurze Zeichenfolgen als "Hallo Welt" aus der Frage, aber wenn die Zeichenfolge sehr lang ist, sagen wir das trHandbuch, dann ist das Gegenteil der Fall, da die Zeit des Laichens der Prozesse im Vergleich zur Zeit der Zeichenfolgenmanipulation vernachlässigbar ist sedund awksind engagiert. Wenn der String extrem lang ist, sagen wir das gesamte Bash-Handbuch, kann Bash aufgrund einiger interner Einschränkungen einfach ablehnen, ganz fortzufahren.
Jimmy
2
@ jw013 I String - Manipulation Code, bash ist behauptet ist weniger effizient dann gewidmet Werkzeuge wie sed, awk, troder ähnliches. Schauen Sie sich die gena2x-Antwort an, die ich vor einiger Zeit bearbeitet habe, und fügen Sie genau diese Informationen hinzu: unix.stackexchange.com/questions/162221/… Sie können sie mit der Antwort von terdon auf dieselbe Frage vergleichen, bei der er Zeit für kurze Zeichenfolgen gibt, in denen Das Laichen von Fällen dauert am meisten. Sie können es selbst testen und das Ergebnis veröffentlichen.
Jimmy
1
@Miati Warum denkst du, ist dieses Extra read x; echo $xbesser für die Leistung? Die Syntax sieht nicht kürzer oder sauberer aus. x=${x// /_}; x=${x^^}ist ein viel prägnanterer Weg, um das Gleiche zu tun wie {read x; echo ${x.... In Bezug auf die Leistung hat @jimmij darauf hingewiesen, dass tr/ sedschneller wäre als bash, wenn die Anzahl der Gabeln gleich wäre. Die Verwendung eines Rohrs führt immer zu einem zusätzlichen Prozess, sodass das Argument des Speicherns einer Gabel nicht mehr gilt. Wenn Sie also Pipes verwenden, verwenden Sie einfach sed/ tretc. Wenn Sie dies in Bash tun können, tun Sie dies und überspringen Sie diesen read x; echo $xUnsinn.
jw013

Antworten:

9

Was Jimij gesagt hat. Sein letztes Beispiel ist das, was Sie dem am nächsten kommen können, was Sie in Ihrem Ausdruck versuchen.

Hier ist eine Variante zu diesem Thema:

echo 'hello world'|echo $(read s;s=${s^^};echo ${s// /_})

Ich würde gerne verwenden tr, da es ziemlich schnell ist.

echo 'hello world'|tr ' [:lower:]' '_[:upper:]'

Ich nehme an, es ist eine Schande, dass bash keine verschachtelte Parametererweiterung zulässt. OTOH, die Verwendung solcher verschachtelter Ausdrücke kann leicht zu Code führen, dessen Lesen schmerzhaft ist. Wenn Sie nicht wirklich brauchen, dass die Dinge so schnell wie möglich laufen, ist es besser, Code zu schreiben, der einfach zu lesen, zu verstehen und zu warten ist, als clever aussehenden Code, der eine PITA zum Debuggen ist. Und wenn Sie wirklich Dinge mit Höchstgeschwindigkeit erledigen müssen, sollten Sie kompilierten Code verwenden, kein Skript.

PM 2Ring
quelle
7

Sie können Parametererweiterungen nicht so übergeben. Wenn Sie sich auf die xVerwendung von $Symbolen wie im "${x}"Formular beziehen , muss es sich um einen echten Variablennamen handeln, nicht um eine Standardeingabe, zumindest nicht um bash. In können zshSie verschachtelte Parametersubstitutionen folgendermaßen durchführen:

$ x=''hello world'
$ echo ${${x// /_}:u}
HELLO_WORLD

(Hinweis: :uist für zshdas gleiche wie ^^für bash)

Das Verschachteln in Bash ist nicht möglich, und ich denke, was Sie in Frage gestellt haben, ist das Beste, was man bekommen kann. Wenn Sie jedoch aus irgendeinem seltsamen Grund Pipes in die Gleichung einbeziehen müssen, sollten Sie Folgendes versuchen:

$ echo 'hello world' | { read x; echo "${x// /_}"; } | { read y; echo "${y^^}"; }
HELLO_WORLD
jimmij
quelle
1
In Anbetracht unserer jüngsten Konversation darüber, wie tr/ sedschneller als bashbei der Zeichenfolgenverarbeitung ist und wie Sie Pipes verwenden, um Zeichenfolgen über Standard-E / A zu übergeben, sehe ich buchstäblich Nullpunkt für die Ausführung dieser Operationen in Bash im Gegensatz zu tr/ sed. Warum sollte man jemals | { read x; echo $x... }im Gegensatz zu einem | sed, der das Gleiche tut?
jw013
1
@ jw013 ehrlich gesagt sehe ich so gut wie keinen Sinn. Es ist nur ein Beispiel zu gewaltsam Rohre für das Problem engagieren, weil OP für sie ausdrücklich gefragt und wollte nicht , externe Programme verwenden (beide echound readsind bash Einbauten, so im Prinzip ein wenig schneller). Wie ich bereits in der Antwort geschrieben habe, sind progressive Parametermanipulationen, die OP in der Frage hat, meiner Meinung nach das Beste, was man für diese Aufgabe in Bash bekommen kann. Auf jeden Fall ist das Problem eher akademisch.
Jimmyij