Bash
Bash Parameter Expansion
Sök…
Introduktion
Tecknet $
introducerar parameterutvidgning, kommandosubstitution eller aritmetisk expansion. Parameternamnet eller symbolen som ska utvidgas kan vara inneslutet i hängslen, vilket är valfritt men tjänar till att skydda variabeln som ska utvidgas från tecken omedelbart efter den som kan tolkas som en del av namnet.
Läs mer i Bash Användarmanual .
Syntax
- $ {parameter: offset} # Substring börjar vid offset
- $ {parameter: offset: length} # Substring of length "length" från offset
- $ {# parameter} # Längd på parametern
- $ {parameter / pattern / string} # Ersätt den första förekomsten av mönster med sträng
- $ {parameter // pattern / string} # Ersätt alla förekomster av mönster med sträng
- $ {parameter / # pattern / string} # Ersätt mönster med sträng om mönstret är i början
- $ {parameter /% pattern / string} # Byt ut mönster med sträng om mönstret slutar
- $ {parameter # mönster} # Ta bort kortaste matchning av mönster från början av parametern
- $ {parameter ## pattern} # Ta bort den längsta matchningen av mönster från början av parametern
- $ {parameter% mönster} # Ta bort kortaste matchning av mönster från slutet av parametern
- $ {parameter %% mönster} # Ta bort den längsta matchningen av mönster från slutet av parametern
- $ {parameter: -word} # Expandera till ord om parameter inte är inställd / undefined
- $ {parameter: = word} # Expandera till ord om parameter avmarkeras / undefineras och ställer in parameter
- $ {parameter: + word} # Expandera till ord om parametern är inställd / definierad
Underlag och delstråk
var='0123456789abcdef'
# Define a zero-based offset
$ printf '%s\n' "${var:3}"
3456789abcdef
# Offset and length of substring
$ printf '%s\n' "${var:3:4}"
3456
# Negative length counts from the end of the string
$ printf '%s\n' "${var:3:-5}"
3456789a
# Negative offset counts from the end
# Needs a space to avoid confusion with ${var:-6}
$ printf '%s\n' "${var: -6}"
abcdef
# Alternative: parentheses
$ printf '%s\n' "${var:(-6)}"
abcdef
# Negative offset and negative length
$ printf '%s\n' "${var: -6:-5}"
a
Samma utvidgningar gäller om parametern är en positionsparameter eller elementet i en subskriven array :
# Set positional parameter $1
set -- 0123456789abcdef
# Define offset
$ printf '%s\n' "${1:5}"
56789abcdef
# Assign to array element
myarr[0]='0123456789abcdef'
# Define offset and length
$ printf '%s\n' "${myarr[0]:7:3}"
789
Analoga utvidgningar gäller för positionsparametrar , där offset är en-baserad:
# Set positional parameters $1, $2, ...
$ set -- 1 2 3 4 5 6 7 8 9 0 a b c d e f
# Define an offset (beware $0 (not a positional parameter)
# is being considered here as well)
$ printf '%s\n' "${@:10}"
0
a
b
c
d
e
f
# Define an offset and a length
$ printf '%s\n' "${@:10:3}"
0
a
b
# No negative lengths allowed for positional parameters
$ printf '%s\n' "${@:10:-2}"
bash: -2: substring expression < 0
# Negative offset counts from the end
# Needs a space to avoid confusion with ${@:-10:2}
$ printf '%s\n' "${@: -10:2}"
7
8
# ${@:0} is $0 which is not otherwise a positional parameters or part
# of $@
$ printf '%s\n' "${@:0:2}"
/usr/bin/bash
1
Substringsutvidgning kan användas med indexerade matriser :
# Create array (zero-based indices)
$ myarr=(0 1 2 3 4 5 6 7 8 9 a b c d e f)
# Elements with index 5 and higher
$ printf '%s\n' "${myarr[@]:12}"
c
d
e
f
# 3 elements, starting with index 5
$ printf '%s\n' "${myarr[@]:5:3}"
5
6
7
# The last element of the array
$ printf '%s\n' "${myarr[@]: -1}"
f
Längd på parametern
# Length of a string
$ var='12345'
$ echo "${#var}"
5
Observera att det är längden i antal tecken som inte nödvändigtvis är samma som antalet byte (som i UTF-8 där de flesta tecken är kodade i mer än en byte), och inte heller antalet glyfer / grafema (av vilka några är kombinationer av tecken), och det är inte nödvändigtvis samma som visningsbredden.
# Number of array elements
$ myarr=(1 2 3)
$ echo "${#myarr[@]}"
3
# Works for positional parameters as well
$ set -- 1 2 3 4
$ echo "${#@}"
4
# But more commonly (and portably to other shells), one would use
$ echo "$#"
4
Ändra fallet med alfabetiska tecken
För stora versaler
$ v="hello"
# Just the first character
$ printf '%s\n' "${v^}"
Hello
# All characters
$ printf '%s\n' "${v^^}"
HELLO
# Alternative
$ v="hello world"
$ declare -u string="$v"
$ echo "$string"
HELLO WORLD
För små bokstäver
$ v="BYE"
# Just the first character
$ printf '%s\n' "${v,}"
bYE
# All characters
$ printf '%s\n' "${v,,}"
bye
# Alternative
$ v="HELLO WORLD"
$ declare -l string="$v"
$ echo "$string"
hello world
Växla fall
$ v="Hello World"
# All chars
$ echo "${v~~}"
hELLO wORLD
$ echo "${v~}"
# Just the first char
hello World
Parameter indirektion
Bash
indirection tillåter att få värdet på en variabel vars namn finns i en annan variabel. Exempel på variabler:
$ red="the color red"
$ green="the color green"
$ color=red
$ echo "${!color}"
the color red
$ color=green
$ echo "${!color}"
the color green
Några fler exempel som visar den indirekta expansionsanvändningen:
$ foo=10
$ x=foo
$ echo ${x} #Classic variable print
foo
$ foo=10
$ x=foo
$ echo ${!x} #Indirect expansion
10
Ytterligare ett exempel:
$ argtester () { for (( i=1; i<="$#"; i++ )); do echo "${i}";done; }; argtester -ab -cd -ef
1 #i expanded to 1
2 #i expanded to 2
3 #i expanded to 3
$ argtester () { for (( i=1; i<="$#"; i++ )); do echo "${!i}";done; }; argtester -ab -cd -ef
-ab # i=1 --> expanded to $1 ---> expanded to first argument sent to function
-cd # i=2 --> expanded to $2 ---> expanded to second argument sent to function
-ef # i=3 --> expanded to $3 ---> expanded to third argument sent to function
Standardvärdesersättning
${parameter:-word}
Om parametern är inställd eller noll, ersätts utvidgningen av ord. Annars ersätts parametervärdet.
$ unset var
$ echo "${var:-XX}" # Parameter is unset -> expansion XX occurs
XX
$ var="" # Parameter is null -> expansion XX occurs
$ echo "${var:-XX}"
XX
$ var=23 # Parameter is not null -> original expansion occurs
$ echo "${var:-XX}"
23
${parameter:=word}
Om parametern är inställd eller noll tilldelas utvidgningen av ord till parametern. Värdet på parametern ersätts sedan. Positioneringsparametrar och specialparametrar kanske inte tilldelas på detta sätt.
$ unset var
$ echo "${var:=XX}" # Parameter is unset -> word is assigned to XX
XX
$ echo "$var"
XX
$ var="" # Parameter is null -> word is assigned to XX
$ echo "${var:=XX}"
XX
$ echo "$var"
XX
$ var=23 # Parameter is not null -> no assignment occurs
$ echo "${var:=XX}"
23
$ echo "$var"
23
Fel om variabeln är tom eller inte inställd
Semantiken för detta liknar den för standardvärdesersättning, men istället för att ersätta ett standardvärde, felar det ut med det medföljande felmeddelandet. Formerna är ${VARNAME?ERRMSG}
och ${VARNAME:?ERRMSG}
. Formuläret med :
kommer att fel vår om variabeln är inställd eller tom , medan formen utan kommer bara att fel ut om variabeln är inställd . Om ett fel kastas, ERRMSG
ut och utgångskoden är inställd på 1
.
#!/bin/bash
FOO=
# ./script.sh: line 4: FOO: EMPTY
echo "FOO is ${FOO:?EMPTY}"
# FOO is
echo "FOO is ${FOO?UNSET}"
# ./script.sh: line 8: BAR: EMPTY
echo "BAR is ${BAR:?EMPTY}"
# ./script.sh: line 10: BAR: UNSET
echo "BAR is ${BAR?UNSET}"
Kör det fullständiga exemplet ovanför vart och ett av de felaktiga ekoutdragen måste kommenteras för att fortsätta.
Radera ett mönster från början av en sträng
Kortaste matchen:
$ a='I am a string'
$ echo "${a#*a}"
m a string
Längsta match:
$ echo "${a##*a}"
string
Radera ett mönster från slutet av en sträng
Kortaste matchen:
$ a='I am a string'
$ echo "${a%a*}"
I am
Längsta match:
$ echo "${a%%a*}"
I
Byt ut mönstret i strängen
Första matchen:
$ a='I am a string'
$ echo "${a/a/A}"
I Am a string
Alla matcher:
$ echo "${a//a/A}"
I Am A string
Match i början:
$ echo "${a/#I/y}"
y am a string
Match i slutet:
$ echo "${a/%g/N}"
I am a strinN
Byt ut ett mönster med ingenting:
$ echo "${a/g/}"
I am a strin
Lägg till prefix till arrayobjekt:
$ A=(hello world)
$ echo "${A[@]/#/R}"
Rhello Rworld
Munging under expansion
Variabler behöver inte nödvändigtvis expandera till sina värden - underlag kan extraheras under expansion, vilket kan vara användbart för att extrahera filändelser eller delar av sökvägar. Glödande karaktärer behåller sin vanliga betydelse, så .*
Hänvisar till en bokstavlig prick, följt av valfri teckenföljd; det är inte ett vanligt uttryck.
$ v=foo-bar-baz
$ echo ${v%%-*}
foo
$ echo ${v%-*}
foo-bar
$ echo ${v##*-}
baz
$ echo ${v#*-}
bar-baz
Det är också möjligt att utöka en variabel med ett standardvärde - säg att jag vill åberopa användarens redigerare, men om de inte har ställt in en skulle jag vilja ge dem vim
.
$ EDITOR=nano
$ ${EDITOR:-vim} /tmp/some_file
# opens nano
$ unset EDITOR
$ $ ${EDITOR:-vim} /tmp/some_file
# opens vim
Det finns två olika sätt att utföra denna utvidgning, som skiljer sig i om den relevanta variabeln är tom eller inte inställd. Använda :-
kommer att använda standarden om variabeln är antingen inställd eller tom, medan -
bara använder standarden om variabeln är inställd, men kommer att använda variabeln om den är inställd på den tomma strängen:
$ a="set"
$ b=""
$ unset c
$ echo ${a:-default_a} ${b:-default_b} ${c:-default_c}
set default_b default_c
$ echo ${a-default_a} ${b-default_b} ${c-default_c}
set default_c
I likhet med standardvärden kan alternativ ges; där en standard används om en viss variabel inte är tillgänglig, används ett alternativ om variabeln är tillgänglig.
$ a="set"
$ b=""
$ echo ${a:+alternative_a} ${b:+alternative_b}
alternative_a
Att notera att dessa utvidgningar kan häckas, att använda alternativ blir särskilt användbart när man tillhandahåller argument till kommandoradsflaggor;
$ output_file=/tmp/foo
$ wget ${output_file:+"-o ${output_file}"} www.stackexchange.com
# expands to wget -o /tmp/foo www.stackexchange.com
$ unset output_file
$ wget ${output_file:+"-o ${output_file}"} www.stackexchange.com
# expands to wget www.stackexchange.com
Parameterutvidgning och filnamn
Du kan använda Bash Parameter Expansion för att emulera vanliga basename
som basename
och dirname
.
Vi kommer att använda detta som vår exempelväg:
FILENAME="/tmp/example/myfile.txt"
dirname
emulerar du dirname
och returnerar dirname
:
echo "${FILENAME%/*}"
#Out: /tmp/example
basename $FILENAME
emulerar du basename $FILENAME
och returnerar filnamnet på en filväg:
echo "${FILENAME##*/}"
#Out: myfile.txt
För att emulera basename $FILENAME .txt
och returnera filnamnet utan .txt.
förlängning:
BASENAME="${FILENAME##*/}"
echo "${BASENAME%%.txt}"
#Out: myfile