Parameter Substitution (Bash): verschil tussen versies

Uit De Vliegende Brigade
Naar navigatie springen Naar zoeken springen
(24 tussenliggende versies door dezelfde gebruiker niet weergegeven)
Regel 1: Regel 1:
''Parameter substitution'' of ''parameter expansion'' betekent dat in een Bash-expressie een ''parameter'' of ''variabele'' wordt vervangen door de inhoud van die variabele. Parameter expansion wordt aangegeven met <code>$</code>, vaak in combinatie met accolades: <code>${}</code>, of nog completer: <code>${parameter}</code>.
+
''Parameter substitution'', ''parameter expansion'' of ''shell parameter expansion'' betekent dat in een Bash-expressie een ''parameter'' of ''variabele'' wordt vervangen door de inhoud van die variabele, al of niet in combinatie met een bewerking.  
  
Het principe is heel simpel en het weergeven van de waarde van een variabele is hier zelfs al een voorbeeld van:
+
Parameter expansion wordt aangegeven met <code>$</code>, vaak in combinatie met accolades: <code>${}</code>, of nog completer: <code>${parameter}</code>.
 +
 
 +
== ${} ==
 +
 
 +
Zoiets simpels als het weergeven van de waarde van een variabele, is al een voorbeeld van parameter substitution:
  
 
<pre>
 
<pre>
 
$ a=12
 
$ a=12
 
$ echo $a
 
$ echo $a
 +
 +
12
 +
</pre>
 +
 +
Door accolades toe te voegen, is het concept van ''expansie'' misschien nog duidelijker. Ihb, dat <code>$</code> de operator is. Het is niet onderdeel van de naam van de variabele: Het gedeelte binnen de accolades krijgt namelijk geen $-teken:
 +
 +
<pre>
 +
$ a=12
 +
$ echo ${a}
 +
 +
12
 +
</pre>
 +
 +
== ${parameter:-word} ==
 +
 +
Gebruik deze syntaxis om <code>parameter</code> te vervangen door ''literal'' <code>word</code> als deze eerste leeg is. Zoiets als <code>ifnull(a, b)</code> in SQL:
 +
 +
<pre>
 +
# De parameter bestaat en heeft een waarde:
 +
 +
$ i1="Hello, world!"
 +
$ echo ${i1:-De parameter is leeg!}
 +
 +
Hello, world!
 +
</pre>
 +
 +
<pre>
 +
# De parameter bestaat niet - De literal wordt weergegeven
 +
 +
$ i1="Hello, world!"
 +
$ echo ${i3:-De parameter is leeg!}
 +
 +
De parameter is leeg!
 +
</pre>
 +
 +
Wil je in plaats van een ''literal'' een parameter meegeven? Geen probleem: Daar gaat dit artikel over:
 +
 +
<pre>
 +
$ i1="Hello, world!"
 +
$ i2="Vervanging"
 +
$ echo ${i3:-${i2}}
 +
 +
Vervanging
 +
</pre>
 +
 +
Als de parameter wel bestaat, maar leeg is:
 +
 +
<pre>
 +
$ i1=
 +
$ echo ${i1:-Leeg}
 +
 +
Leeg
 
</pre>
 
</pre>
  
Afhankelijk van de gebruikte syntaxis, kun je een hoop truken uithalen, waaronder ''find-&-replace''. Dat maakt dit een krachtig stuk gereedschap.
+
== ${parameter/pattern/string} ==
  
 +
Parameter expansion kun je gebruiken voor ''find-&-replace'':
  
 +
<pre>
 +
$ i1="Hello, world!"
 +
$ echo ${i1/world/moon}
 +
 +
Hello, moon!
 +
</pre>
  
 +
Standaard wordt alleen de eerste ''occurence'' van ''pattern'' vervangen:
  
 +
<pre>
 +
$ i1="Hello, world1, world2 & world3!"
 +
$ echo ${i1/world/moon}
  
Plus nog wat extra's waaronder ''find-&-replace''. Krachtig spul!
+
Hello, moon1, world2 & world3!
 +
</pre>
  
Gelijk al een raar voorbeeld: Het eerste argument moet een variabele zijn, maar de tweede en derde zijn ''literals''???
+
Dat kun je aanpassen door ''pattern'' met een <code>/</code> te laten beginnen:
  
 
<pre>
 
<pre>
naam="Janneke"
+
$ i1="Hello, world1, world2 & world3!"
echo ${naam/a/A}
+
$ echo ${i1//world/moon}
JAnneke
 
  
 +
Hello, moon1, moon2 & moon3!
 +
</pre>
  
# Dit doet nix, want variable heeft geen waarde:
+
[https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html Meer]:
#
 
echo ${Jasper/a/A}
 
  
 +
<pre>
 +
The pattern is expanded to produce a pattern just as in filename expansion. Parameter is expanded and the
 +
longest match of pattern against its value is replaced with string. The match is performed according to
 +
the rules described below (see Pattern Matching). If pattern begins with ‘/’, all matches of pattern are
 +
replaced with string. Normally only the first match is replaced. If pattern begins with ‘#’, it must match
 +
at the beginning of the expanded value of parameter. If pattern begins with ‘%’, it must match at the end
 +
of the expanded value of parameter. If string is null, matches of pattern are deleted and the / following
 +
pattern may be omitted. If the nocasematch shell option (see the description of shopt in The Shopt
 +
Builtin) is enabled, the match is performed without regard to the case of alphabetic characters. If
 +
parameter is ‘@’ or ‘*’, the substitution operation is applied to each positional parameter in turn, and
 +
the expansion is the resultant list. If parameter is an array variable subscripted with ‘@’ or ‘*’, the
 +
substitution operation is applied to each member of the array in turn, and the expansion is the resultant
 +
list.
 +
</pre>
  
# Dit geeft foutmelding - Snap ik niet
+
Some inspiration:
#
+
 
echo ${"Jasper"/a/A}
+
* https://stackoverflow.com/questions/15116427/bash-string-replacement-gives-me-bad-substitution
echo ${"Jasper"/a/A}: bad substitution
+
* https://stackoverflow.com/questions/8960677/string-replacement-in-bash-bad-substitution-error
 +
 
 +
Let op: Je kunt maar één substitutie per keer toepassen: https://stackoverflow.com/questions/25996806/multiple-substitutions-on-a-string-in-bash
 +
 
 +
== Convert to uppercase ==
 +
 
 +
[https://www.cyberciti.biz/tips/bash-shell-parameter-substitution-2.html]:
 +
 
 +
<pre>
 +
$ name="vivek"
 +
$ echo $name
 +
vivek
 +
 
 +
$ echo ${name^}
 +
Vivek
 +
 
 +
$ echo ${name^^}
 +
VIVEK
 
</pre>
 
</pre>
 +
 +
== Casus: Extra line breaks product_cat (aug. 2021) ==
 +
 +
WordPress product_cat-taxon-beschrijvingen worden via WP-CLI en Bash bijgewerkt. Ik gebruik ''parameter substitution'' for ''find-&-replace, met code zoals dit:
 +
 +
<pre>
 +
i1=$(wp wc product_cat --user=4 get 18869 --field="description")
 +
wp wc product_cat --user=4 update 18869 --description="${i1/Alle widgets voor/All widgets for}"
 +
</pre>
 +
 +
Er wordt echter een karakter <code>0a</code> (''line feed'') toegevoegd aan het begin van de string. Hoe kan dat? Hoe verhinder ik dat?
 +
 +
{|
 +
|[[file:20210802-0905.png|thumb|Zes ''line feeds'' vóór de eigenlijke tekst (ik heb deze routine vermoedelijk al zes keer uitgevoerd)]]
 +
|[[file:20210802-0906.png|thumb|Het gaat inderdaad om ''line feeds'': <code>0a</code>]]
 +
|}
  
 
== Zie ook ==
 
== Zie ook ==
Regel 43: Regel 157:
 
* https://tldp.org/LDP/abs/html/parameter-substitution.html
 
* https://tldp.org/LDP/abs/html/parameter-substitution.html
 
* https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
 
* https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
 +
* https://www.cyberciti.biz/tips/bash-shell-parameter-substitution-2.html

Versie van 27 mei 2022 11:58

Parameter substitution, parameter expansion of shell parameter expansion betekent dat in een Bash-expressie een parameter of variabele wordt vervangen door de inhoud van die variabele, al of niet in combinatie met een bewerking.

Parameter expansion wordt aangegeven met $, vaak in combinatie met accolades: ${}, of nog completer: ${parameter}.

${}

Zoiets simpels als het weergeven van de waarde van een variabele, is al een voorbeeld van parameter substitution:

$ a=12
$ echo $a

12

Door accolades toe te voegen, is het concept van expansie misschien nog duidelijker. Ihb, dat $ de operator is. Het is niet onderdeel van de naam van de variabele: Het gedeelte binnen de accolades krijgt namelijk geen $-teken:

$ a=12
$ echo ${a}

12

${parameter:-word}

Gebruik deze syntaxis om parameter te vervangen door literal word als deze eerste leeg is. Zoiets als ifnull(a, b) in SQL:

# De parameter bestaat en heeft een waarde:

$ i1="Hello, world!"
$ echo ${i1:-De parameter is leeg!}

Hello, world!
# De parameter bestaat niet - De literal wordt weergegeven

$ i1="Hello, world!"
$ echo ${i3:-De parameter is leeg!}

De parameter is leeg!

Wil je in plaats van een literal een parameter meegeven? Geen probleem: Daar gaat dit artikel over:

$ i1="Hello, world!"
$ i2="Vervanging"
$ echo ${i3:-${i2}}

Vervanging

Als de parameter wel bestaat, maar leeg is:

$ i1=
$ echo ${i1:-Leeg}

Leeg

${parameter/pattern/string}

Parameter expansion kun je gebruiken voor find-&-replace:

$ i1="Hello, world!"
$ echo ${i1/world/moon}

Hello, moon!

Standaard wordt alleen de eerste occurence van pattern vervangen:

$ i1="Hello, world1, world2 & world3!"
$ echo ${i1/world/moon}

Hello, moon1, world2 & world3!

Dat kun je aanpassen door pattern met een / te laten beginnen:

$ i1="Hello, world1, world2 & world3!"
$ echo ${i1//world/moon}

Hello, moon1, moon2 & moon3!

Meer:

The pattern is expanded to produce a pattern just as in filename expansion. Parameter is expanded and the 
longest match of pattern against its value is replaced with string. The match is performed according to 
the rules described below (see Pattern Matching). If pattern begins with ‘/’, all matches of pattern are 
replaced with string. Normally only the first match is replaced. If pattern begins with ‘#’, it must match 
at the beginning of the expanded value of parameter. If pattern begins with ‘%’, it must match at the end 
of the expanded value of parameter. If string is null, matches of pattern are deleted and the / following 
pattern may be omitted. If the nocasematch shell option (see the description of shopt in The Shopt 
Builtin) is enabled, the match is performed without regard to the case of alphabetic characters. If 
parameter is ‘@’ or ‘*’, the substitution operation is applied to each positional parameter in turn, and 
the expansion is the resultant list. If parameter is an array variable subscripted with ‘@’ or ‘*’, the 
substitution operation is applied to each member of the array in turn, and the expansion is the resultant 
list.

Some inspiration:

Let op: Je kunt maar één substitutie per keer toepassen: https://stackoverflow.com/questions/25996806/multiple-substitutions-on-a-string-in-bash

Convert to uppercase

[1]:

$ name="vivek"
$ echo $name
vivek

$ echo ${name^}
Vivek

$ echo ${name^^}
VIVEK

Casus: Extra line breaks product_cat (aug. 2021)

WordPress product_cat-taxon-beschrijvingen worden via WP-CLI en Bash bijgewerkt. Ik gebruik parameter substitution for find-&-replace, met code zoals dit:

i1=$(wp wc product_cat --user=4 get 18869 --field="description")
wp wc product_cat --user=4 update 18869 --description="${i1/Alle widgets voor/All widgets for}"

Er wordt echter een karakter 0a (line feed) toegevoegd aan het begin van de string. Hoe kan dat? Hoe verhinder ik dat?

Zes line feeds vóór de eigenlijke tekst (ik heb deze routine vermoedelijk al zes keer uitgevoerd)
Het gaat inderdaad om line feeds: 0a

Zie ook

Bronnen