Bash
Podział słów
Szukaj…
Składnia
- Ustaw IFS na nowy wiersz: IFS = $ '\ n'
- Ustaw IFS na nullstring: IFS =
- Ustaw IFS na / character: IFS = /
Parametry
Parametr | Detale |
---|---|
IFS | Separator pola wewnętrznego |
-x | Drukuj polecenia i ich argumenty podczas ich wykonywania (opcja Shell) |
Uwagi
- Podział słów nie jest wykonywany podczas przypisań, np.
newvar=$var
- Dzielenie wyrazów nie jest wykonywane w konstrukcie
[[ ... ]]
- Użyj podwójnych cudzysłowów na zmiennych, aby zapobiec dzieleniu słów
Podział za pomocą IFS
Aby być bardziej przejrzystym, stwórzmy skrypt o nazwie showarg
:
#!/usr/bin/env bash
printf "%d args:" $#
printf " <%s>" "$@"
echo
Zobaczmy teraz różnice:
$ var="This is an example"
$ showarg $var
4 args: <This> <is> <an> <example>
$var
jest podzielony na 4 argumenty.IFS
jest znakami spacji, dlatego dzielenie słów występowało w spacjach
$ var="This/is/an/example"
$ showarg $var
1 args: <This/is/an/example>
W powyższym przypadku nie doszło do podziału słów, ponieważ nie znaleziono znaków
IFS
.
Teraz IFS=/
$ IFS=/
$ var="This/is/an/example"
$ showarg $var
4 args: <This> <is> <an> <example>
$var
dzieli się na 4 argumenty, a nie jeden argument.
Co, kiedy i dlaczego?
Gdy powłoka wykonuje interpretację parametrów , podstawianie poleceń , interpretację zmiennych lub arytmetyki , skanuje w poszukiwaniu granic słów. Jeśli zostanie znaleziona granica słowa, wynik zostanie podzielony na wiele słów w tej pozycji. Granica słowa jest zdefiniowana przez zmienną powłoki IFS
(Internal Field Separator). Domyślnymi wartościami dla IFS są spacja, tabulator i nowa linia, tzn. Dzielenie słów nastąpi na tych trzech białych znakach, jeśli nie zostanie to wyraźnie zabronione.
set -x
var='I am
a
multiline string'
fun() {
echo "-$1-"
echo "*$2*"
echo ".$3."
}
fun $var
W powyższym przykładzie działa funkcja fun
:
fun I am a multiline string
$var
jest podzielony na 5 args, tylkoI
,am
i zostanie wydrukowany.a
IFS i dzielenie słów
Zobacz, co, kiedy i dlaczego, jeśli nie wiesz o powiązaniu IFS z dzieleniem słów
ustawmy IFS tylko na znak spacji:
set -x
var='I am
a
multiline string'
IFS=' '
fun() {
echo "-$1-"
echo "*$2*"
echo ".$3."
}
fun $var
Tym razem dzielenie słów działa tylko na spacje. Funkcja fun
zostanie wykonana w następujący sposób:
fun I 'am
a
multiline' string
$var
jest podzielony na 3 argumenty.I
,am\na\nmultiline
istring
zostanie wydrukowany
Ustawmy IFS tylko na nową linię:
IFS=$'\n'
...
Teraz fun
zostanie wykonana w następujący sposób:
fun 'I am' a 'multiline string'
$var
jest podzielony na 3 argumenty.I am
, ,a
multiline string
zostanie wydrukowany
Zobaczmy, co się stanie, jeśli ustawimy IFS na nullstring:
IFS=
...
Tym razem fun
zostanie wykonana w następujący sposób:
fun 'I am
a
multiline string'
$var
nie jest podzielona, tzn. pozostała pojedynczym argumentem.
Możesz zapobiec dzieleniu słów, ustawiając IFS na nullstring
Ogólnym sposobem zapobiegania dzieleniu słów jest użycie podwójnego cudzysłowu:
fun "$var"
zapobiegnie dzieleniu słów we wszystkich przypadkach omówionych powyżej, tj. funkcja fun
będzie wykonywana tylko z jednym argumentem.
Złe efekty dzielenia słów
$ a='I am a string with spaces'
$ [ $a = $a ] || echo "didn't match"
bash: [: too many arguments
didn't match
[ $a = $a ]
zostało zinterpretowane jako[ I am a string with spaces = I am a string with spaces ]
.[
to polecenietest
dla któregoI am a string with spaces
nie jest pojedynczym argumentem, a raczej 6 argumentami !!
$ [ $a = something ] || echo "didn't match"
bash: [: too many arguments
didn't match
[ $a = something ]
interpretowano jako[ I am a string with spaces = something ]
$ [ $(grep . file) = 'something' ]
bash: [: too many arguments
Polecenie
grep
zwraca łańcuch wielowierszowy ze spacjami, abyś mógł sobie wyobrazić, ile jest argumentów ...: D
Zobacz, co, kiedy i dlaczego podstawy.
Przydatność podziału słów
W niektórych przypadkach dzielenie słów może być przydatne:
Wypełnianie tablicy:
arr=($(grep -o '[0-9]\+' file))
Spowoduje to wypełnienie
arr
wszystkimi wartościami liczbowymi znalezionymi w pliku
Pętle przez słowa oddzielone spacjami:
words='foo bar baz'
for w in $words;do
echo "W: $w"
done
Wynik:
W: foo
W: bar
W: baz
Przekazywanie parametrów oddzielonych spacją, które nie zawierają białych spacji:
packs='apache2 php php-mbstring php-mysql'
sudo apt-get install $packs
lub
packs='
apache2
php
php-mbstring
php-mysql
'
sudo apt-get install $packs
Spowoduje to zainstalowanie pakietów. Jeśli podwójnie zacytujesz
$packs
, spowoduje to błąd.
Unquoetd
$packs
wysyła wszystkie nazwy pakietów rozdzielonych spacjami jako argumenty doapt-get
, podczas gdy cytowanie wyśle ciąg$packs
jako pojedynczy argument, a następnieapt-get
spróbuje zainstalować pakiet o nazwieapache2 php php-mbstring php-mysql
(dla pierwszego), który oczywiście nie istnieje
Zobacz, co, kiedy i dlaczego podstawy.
Podział według zmian separatora
Możemy po prostu dokonać prostej zamiany separatorów z odstępu na nowy wiersz, jak w poniższym przykładzie.
echo $sentence | tr " " "\n"
Dzieli wartość sentence
zmiennego i pokazuje odpowiednio wiersz po wierszu.