Stringvariable ändern und abfragen in einem Schritt

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
Benutzeravatar
Ragoutc
Beiträge: 3
Registriert: 09.01.2022 13:26:18

Stringvariable ändern und abfragen in einem Schritt

Beitrag von Ragoutc » 29.04.2022 19:54:31

Hallo zusammen,

hier eine Frage zu bash: Gibt es in der eine Möglichkeit, eine Stringvariable gleichzeitig zu ändern und abzufragen?

Code: Alles auswählen

V=Hallo
echo $V+=" Welt"
echo $V
Beide echo-Befehle sollten "Hallo Welt" ausgeben.

Bei Integer-Variablen funktioniert das wunderbar:

Code: Alles auswählen

v=2
echo $(( v+=5 ))
ergibt ebenso:

Code: Alles auswählen

echo $v
# 7
Vielen Dank für wertvolle Tipps
Grüße
Ragoutc
---------------------------------------
Openmediavault 6 (Debian 10.11)

Ich denke, also bin ich.
Manche sind trotzdem!

buddy67
Beiträge: 169
Registriert: 30.06.2016 22:52:15

Re: Stringvariable ändern und abfragen in einem Schritt

Beitrag von buddy67 » 03.05.2022 19:25:29

V=Hallo
echo $V" Welt"

JTH
Moderator
Beiträge: 3023
Registriert: 13.08.2008 17:01:41
Wohnort: Berlin

Re: Stringvariable ändern und abfragen in einem Schritt

Beitrag von JTH » 03.05.2022 20:17:14

Ragoutc hat geschrieben: ↑ zum Beitrag ↑
29.04.2022 19:54:31
hier eine Frage zu bash: Gibt es in der eine Möglichkeit, eine Stringvariable gleichzeitig zu ändern und abzufragen?
Kurze Antwort: Nein, nicht dass ich wüsste und so wie du es wahrscheinlich suchst.

Außer die Variable ist noch nicht gesetzt (oder leer). Dann kann Parameterexpansion das:

Code: Alles auswählen

echo "${var:=Hallo, Forum!}"
echo "$var"
gibt zweimal „Hallo, Forum!“ aus.

Man könnte sich was basteln, das die Aufgabe erfüllt – wegen declare -n wirklich Bash-spezifisch. Sonst müsste man es mit einem zweiten eval lösen:

Code: Alles auswählen

append_and_eval()                                                                                                                           
{                                                                                                                                           
        declare -n v=$1 && v+=$2 && eval "$3"                                                                                               
}

var="Hallo, "
append_and_eval var "Forum!" 'echo "$var"'                                                                                                  
echo "$var"
gibt wiederum zweimal „Hallo, Forum!“ aus. Funktioniert auch mit vorher nicht gesetzter Variable. Aber das sieht mir nicht besonders praktisch aus – das dritte Argument muss in einfache Anführungszeichen oder aufwendig escapet werden.

Was ist denn der Hintergrund für deine Frage? Vielleicht kann man es anders lösen?
Manchmal bekannt als Just (another) Terminal Hacker.

Benutzeravatar
Meillo
Moderator
Beiträge: 8820
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Stringvariable ändern und abfragen in einem Schritt

Beitrag von Meillo » 03.05.2022 21:25:59

Ich haette das zu bieten:

Code: Alles auswählen

:-/ v=hello

:-/ v+=" world" eval echo \$v
hello world

:-/ echo $v                   
hello world
... das ist aber auch nicht gerade schoener.

Ansonsten hat es JTH schon gut getroffen mit seiner Antwort. Den direkten Weg, nach dem du fragst, gibt es vermutlich nicht (denn sonst wuerden die Shell-Vielnutzer sicherlich kennen).
Use ed once in a while!

JTH
Moderator
Beiträge: 3023
Registriert: 13.08.2008 17:01:41
Wohnort: Berlin

Re: Stringvariable ändern und abfragen in einem Schritt

Beitrag von JTH » 03.05.2022 22:17:06

Meillo hat geschrieben: ↑ zum Beitrag ↑
03.05.2022 21:25:59
Ich haette das zu bieten:
Auch im Ansatz ’ne nette und kürzere Idee. Scheiterte bei mir allerdings grad auf diesem Wege:

Code: Alles auswählen

$ v=Hello
$ v+=" world" eval echo \$v
Hello world
$ echo "$v"
Hello
Zumindest nicht mit bash und zsh, die ich hier grad greifbar hab. Ist das bei dir noch eine andere Shell? (da)sh wirds nicht können, da += dort nicht vorhanden ist.

Dürfte auch aus der Theorie (soweit mir bekannt) nicht gehen, da ’ne Zuweisung vor einem Kommando eine temporäre Umgebungsvariable für dieses Kommando ist, aber keine Variable (-nzuweisung) im aufrufenden Shell-Scope.
Manchmal bekannt als Just (another) Terminal Hacker.

Benutzeravatar
Meillo
Moderator
Beiträge: 8820
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Stringvariable ändern und abfragen in einem Schritt

Beitrag von Meillo » 03.05.2022 22:47:08

JTH hat geschrieben: ↑ zum Beitrag ↑
03.05.2022 22:17:06
Meillo hat geschrieben: ↑ zum Beitrag ↑
03.05.2022 21:25:59
Ich haette das zu bieten:
Auch im Ansatz ’ne nette und kürzere Idee. Scheiterte bei mir allerdings grad auf diesem Wege:

Code: Alles auswählen

$ v=Hello
$ v+=" world" eval echo \$v
Hello world
$ echo "$v"
Hello
Zumindest nicht mit bash und zsh, die ich hier grad greifbar hab. Ist das bei dir noch eine andere Shell?
Ja, eine mksh.

Statt:

Code: Alles auswählen

v+=" foo"
kannst du es natuerlich portabel auch so machen:

Code: Alles auswählen

v="$v foo"
Dürfte auch aus der Theorie (soweit mir bekannt) nicht gehen, da ’ne Zuweisung vor einem Kommando eine temporäre Umgebungsvariable für dieses Kommando ist, aber keine Variable (-nzuweisung) im aufrufenden Shell-Scope.
Da hast du recht. Keine Ahnung warum das geht. Ich habe nur rumprobiert bis es funktioniert hat. :-D

Vielleicht wird keine Subshell geforkt weil eval ein Builtin ist. Vielleicht ist das nur die Auswirkung eines Performancehacks oder so. Koennte man mal genauer recherchieren ... :roll:
Use ed once in a while!

Benutzeravatar
Meillo
Moderator
Beiträge: 8820
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Stringvariable ändern und abfragen in einem Schritt

Beitrag von Meillo » 03.05.2022 23:00:11

Es ist in der mksh die gleiche PID:

Code: Alles auswählen

:-/ echo $$                       
74903

:-/ v="$v world" eval echo '$$ $v'
74903 hello world
In der Bash ist es aber auch die gleiche PID, es geht trotzdem nicht:

Code: Alles auswählen

[meillo@erebus ~]$ v=hello
[meillo@erebus ~]$ echo $$
87058
[meillo@erebus ~]$ v="$v bash" eval echo '$$ $v'
87058 hello bash
[meillo@erebus ~]$ echo $v
hello
In der dash geht es wiederum:

Code: Alles auswählen

:-Q v=hello

:-Q echo $$
19341

:-Q v="$v dash" eval echo '$$ $v'    
19341 hello dash

:-Q echo $v
hello dash
In der Heirloom sh geht es auch:

Code: Alles auswählen

:-Q v=hello

:-Q echo $$
19559

:-Q v="$v heirloom-sh" eval echo '$$ $v'
19559 hello heirloom-sh

:-Q echo $v
hello heirloom-sh
... ist ja komisch. Da muss man wohl noch tiefer graben.
Use ed once in a while!

JTH
Moderator
Beiträge: 3023
Registriert: 13.08.2008 17:01:41
Wohnort: Berlin

Re: Stringvariable ändern und abfragen in einem Schritt

Beitrag von JTH » 03.05.2022 23:10:01

Ah, bunt gemischte Ergebnisse. So will man's doch haben :D Ich denk morgen nochmal drüber nach. Vielleicht liegts auch einfach an der Geschichte der verschiedenen Shells, wie du im anderen Thema gerade angesprochen hast.

… auf jeden Fall muss ich meinen *sh-Fuhrpark anscheinend dringend mal erweitern :wink:
Manchmal bekannt als Just (another) Terminal Hacker.

Benutzeravatar
Meillo
Moderator
Beiträge: 8820
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Stringvariable ändern und abfragen in einem Schritt

Beitrag von Meillo » 04.05.2022 08:38:45

Hier nochmal ein minimaleres Beispiel in der mksh:

Code: Alles auswählen

:-/ v=hello

:-/ v=X echo bar
bar

:-/ echo $v     
hello

:-/ v=X eval echo bar
bar

:-/ echo $v          
X
Vielleicht liegt es am `eval', das ein Special Builtin ist.

Aha, auch bei einem anderen Special Builtin funktioniert es so:

Code: Alles auswählen

:-/ v=hello          

:-/ v=X times        
0m00.00s 0m00.01s
0m00.51s 0m00.02s

:-/ echo $v          
X
Und -- Aha! -- wenn man genau in der Manpage nachliest findet man dort auch die Antwort darauf:
Manpage mksh(1) hat geschrieben: Spe-
cial built-in commands differ from other commands in that the PATH param-
eter is not used to find them, an error during their execution can cause
a non-interactive shell to exit, and parameter assignments that are spec-
ified before the command are kept after the command completes.
;-)

Und -- Tada! -- wenn ich die Bash im POSIX-Mode verwende, dann klappt es dort auch:

Code: Alles auswählen

:-/ ps |grep $$
65194 24  S     0:00.00 bash --posix

:-/ v=hello

:-/ v=X eval echo bar
bar

:-/ echo $v
X

Und weiss man dann wo man in POSIX hinschauen muss, dann findet man die entsprechende Stelle auch:
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_14 hat geschrieben: As described in Simple Commands, variable assignments preceding the invocation of a special built-in utility remain in effect after the built-in completes; this shall not be the case with a regular built-in or other utility.
Damit waere dieses Raetsel geloest. Und es zeigt sich mal wieder: In der Shell ist alles halt so wie es nunmal ist und nicht unbedingt logisch. Sehr vieles sind einfach Zufaelle der ersten Implementierungen (die weniger strukturiert waren als spaetere Sprachen), die fortan gleich bleiben muessen, damit alles kompatibel ist.
Use ed once in a while!

JTH
Moderator
Beiträge: 3023
Registriert: 13.08.2008 17:01:41
Wohnort: Berlin

Re: Stringvariable ändern und abfragen in einem Schritt

Beitrag von JTH » 04.05.2022 09:30:50

Meillo hat geschrieben: ↑ zum Beitrag ↑
04.05.2022 08:38:45
Damit waere dieses Raetsel geloest.
:THX:

Special built-ins … wer kommt denn auf sowas 8O
Manchmal bekannt als Just (another) Terminal Hacker.

Antworten