Bash
Rozszerzenie parametru Bash
Szukaj…
Wprowadzenie
Znak $
wprowadza interpretację parametrów, podstawianie poleceń lub interpretację arytmetyczną. Nazwa parametru lub symbol, który ma zostać rozwinięty, mogą być ujęte w nawiasy klamrowe, które są opcjonalne, ale służą do ochrony zmiennej, która ma zostać rozwinięta przed znakami znajdującymi się bezpośrednio po niej, co może być interpretowane jako część nazwy.
Przeczytaj więcej w Instrukcji obsługi Bash .
Składnia
- $ {parametr: offset} # Podciąg ciąg zaczyna się od offset
- $ {parametr: offset: długość} # Podciąg długości „długość” zaczynający się od offsetu
- $ {# parametr} # Długość parametru
- $ {parametr / wzór / ciąg} # Zamień pierwsze wystąpienie wzoru na ciąg
- $ {parametr // wzorzec / ciąg} # Zamień wszystkie wystąpienia wzorca na ciąg
- $ {parametr / # wzór / ciąg} # Zamień wzór na ciąg, jeśli wzór jest na początku
- $ {parametr /% wzorzec / ciąg} # Zamień wzór na ciąg, jeśli wzór znajduje się na końcu
- $ {parametr # wzorzec} # Usuń najkrótsze dopasowanie wzorca z początku parametru
- $ {parametr ## wzorzec} # Usuń najdłuższe dopasowanie wzorca z początku parametru
- $ {parametr% wzorzec} # Usuń najkrótsze dopasowanie wzorca z końca parametru
- $ {parametr %% wzorzec} # Usuń najdłuższe dopasowanie wzorca z końca parametru
- $ {parametr: -word} # Rozwiń do słowa, jeśli parametr jest nieustawiony / niezdefiniowany
- $ {parametr: = słowo} # Rozwiń do słowa, jeśli parametr jest nieustawiony / niezdefiniowany i ustaw parametr
- $ {parametr: + słowo} # Rozwiń do słowa, jeśli zestaw parametrów / zdefiniowano
Podciągi i podłoża
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
Te same rozszerzenia obowiązują, jeśli parametr jest parametrem pozycyjnym lub elementem tablicy indeksowanej :
# 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
Analogiczne rozszerzenia dotyczą parametrów pozycyjnych , gdzie przesunięcia są oparte na wartościach jeden:
# 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
Rozszerzenia podciągów można używać z tablicami indeksowanymi :
# 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
Długość parametru
# Length of a string
$ var='12345'
$ echo "${#var}"
5
Zauważ, że jest to długość w liczbie znaków, która niekoniecznie jest taka sama jak liczba bajtów (jak w UTF-8, gdzie większość znaków jest zakodowana w więcej niż jednym bajcie), ani liczba glifów / grafemów (niektóre z nich są kombinacje znaków), niekoniecznie jest taki sam jak szerokość wyświetlania.
# 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
Modyfikacja wielkości liter alfabetu
Do wielkich liter
$ 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
Na małe litery
$ 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
Przełącz skrzynkę
$ v="Hello World"
# All chars
$ echo "${v~~}"
hELLO wORLD
$ echo "${v~}"
# Just the first char
hello World
Pośrednia parametryzacja
Pośrednictwo Bash
pozwala uzyskać wartość zmiennej, której nazwa zawarta jest w innej zmiennej. Przykład zmiennych:
$ red="the color red"
$ green="the color green"
$ color=red
$ echo "${!color}"
the color red
$ color=green
$ echo "${!color}"
the color green
Kilka innych przykładów pokazujących użycie pośredniej ekspansji:
$ foo=10
$ x=foo
$ echo ${x} #Classic variable print
foo
$ foo=10
$ x=foo
$ echo ${!x} #Indirect expansion
10
Jeszcze jeden przykład:
$ 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
Podstawienie wartości domyślnej
${parameter:-word}
Jeśli parametr jest nieustawiony lub zerowy, rozwinięcie słowa jest podstawiane. W przeciwnym razie wartość parametru zostanie podstawiona.
$ 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}
Jeśli parametr jest nieustawiony lub zerowy, rozwinięcie słowa jest przypisywane do parametru. Wartość parametru zostaje następnie podstawiona. Parametry pozycyjne i parametry specjalne nie mogą być przypisane w ten sposób.
$ 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
Błąd, jeśli zmienna jest pusta lub nieuzbrojona
Semantyka tego jest podobna do tej z podstawieniem wartości domyślnej, ale zamiast podstawienia wartości domyślnej, pojawia się błąd z podanym komunikatem o błędzie. Formularze to ${VARNAME?ERRMSG}
i ${VARNAME:?ERRMSG}
. Formularz z :
spowoduje błąd nasz, jeśli zmienna jest rozbrojona lub pusta , natomiast formularz bez spowoduje błąd tylko, jeśli zmienna jest rozbrojona . Jeśli zostanie ERRMSG
błąd, ERRMSG
jest wyprowadzany, a kod wyjścia jest ustawiony na 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}"
Uruchom pełny przykład powyżej każdej z błędnych instrukcji echa, aby kontynuować.
Usuń wzór z początku łańcucha
Najkrótszy mecz:
$ a='I am a string'
$ echo "${a#*a}"
m a string
Najdłuższy mecz:
$ echo "${a##*a}"
string
Usuń wzór z końca łańcucha
Najkrótszy mecz:
$ a='I am a string'
$ echo "${a%a*}"
I am
Najdłuższy mecz:
$ echo "${a%%a*}"
I
Zamień wzór w ciągu
Pierwszy mecz:
$ a='I am a string'
$ echo "${a/a/A}"
I Am a string
Wszystkie mecze:
$ echo "${a//a/A}"
I Am A string
Mecz na początku:
$ echo "${a/#I/y}"
y am a string
Mecz na końcu:
$ echo "${a/%g/N}"
I am a strinN
Zamień wzór na nic:
$ echo "${a/g/}"
I am a strin
Dodaj prefiks do elementów tablicy:
$ A=(hello world)
$ echo "${A[@]/#/R}"
Rhello Rworld
Munging podczas ekspansji
Zmienne niekoniecznie muszą być rozwijane do ich wartości - podczas interpretacji można wyodrębnić podciągi, co może być przydatne do wyodrębnienia rozszerzeń plików lub części ścieżek. Globbing znaków ma swoje zwykłe znaczenie, więc .*
Odnosi się do dosłownej kropki, po której następuje dowolna sekwencja znaków; to nie jest wyrażenie regularne.
$ v=foo-bar-baz
$ echo ${v%%-*}
foo
$ echo ${v%-*}
foo-bar
$ echo ${v##*-}
baz
$ echo ${v#*-}
bar-baz
Możliwe jest również rozwinięcie zmiennej przy użyciu wartości domyślnej - powiedzmy, że chcę wywołać edytor użytkownika, ale jeśli nie ustawił, chciałbym dać im vim
.
$ EDITOR=nano
$ ${EDITOR:-vim} /tmp/some_file
# opens nano
$ unset EDITOR
$ $ ${EDITOR:-vim} /tmp/some_file
# opens vim
Istnieją dwa różne sposoby wykonania tego rozszerzenia, różniące się tym, czy odpowiednia zmienna jest pusta, czy rozbrojona. Użycie :-
użyje wartości domyślnej, jeśli zmienna jest nieuzbrojona lub pusta, natomiast -
użyje wartości domyślnej, jeśli zmienna jest rozbrojona, ale użyje zmiennej, jeśli jest ustawiona na pusty ciąg:
$ 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
Podobnie jak w przypadku ustawień domyślnych, można podać alternatywy; w przypadku użycia wartości domyślnej, jeśli dana zmienna nie jest dostępna, alternatywę stosuje się, jeśli zmienna jest dostępna.
$ a="set"
$ b=""
$ echo ${a:+alternative_a} ${b:+alternative_b}
alternative_a
Zwracając uwagę, że rozszerzenia te można zagnieżdżać, stosowanie alternatyw staje się szczególnie przydatne, gdy podaje się argumenty do flag wiersza poleceń;
$ 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
Rozszerzenie parametrów i nazwy plików
Możesz użyć Bash Parameter Expansion do emulacji typowych operacji przetwarzania nazw plików, takich jak basename
i dirname
.
Użyjemy tego jako naszej przykładowej ścieżki:
FILENAME="/tmp/example/myfile.txt"
Emulować dirname
i powrócić nazwy katalogów w ścieżce pliku:
echo "${FILENAME%/*}"
#Out: /tmp/example
Aby emulować basename $FILENAME
i zwrócić nazwę pliku ścieżki pliku:
echo "${FILENAME##*/}"
#Out: myfile.txt
Aby emulować basename $FILENAME .txt
i zwrócić nazwę pliku bez .txt.
rozbudowa:
BASENAME="${FILENAME##*/}"
echo "${BASENAME%%.txt}"
#Out: myfile