Powłoki typu Bourne / POSIX mają operator split + glob i jest on wywoływany za każdym razem, gdy nie podaje się wyrażenia parametru ( $var
, $-
...), podstawienia polecenia ( $(...)
) lub rozszerzenia arytmetycznego ( $((...))
) w kontekście listy.
Właściwie przywołałeś go przez pomyłkę, kiedy to zrobiłeś for name in ${array[@]}
zamiast for name in "${array[@]}"
. (W rzeczywistości powinieneś wystrzegać się tego, że przywołanie takiego operatora przez pomyłkę jest źródłem wielu błędów i luk w zabezpieczeniach ).
Ten operator jest skonfigurowany z $IFS
parametrem specjalnym (aby powiedzieć, na jakie znaki mają się dzielić (choć uważaj, że spacja, tabulator i znak nowej linii są tam specjalnie traktowane)) i -f
opcją wyłączenia ( set -f
) lub włączenia ( set +f
) glob
części.
Zauważ też, że chociaż S
in $IFS
był pierwotnie (w powłoce Bourne'a, skąd $IFS
pochodzi) dla Separatora, w powłokach POSIX, znaki w $IFS
powinny być raczej postrzegane jako separatory lub terminatory (patrz przykład poniżej).
Podzielmy się na _
:
string='var1_var2_var3'
IFS=_ # delimit on _
set -f # disable the glob part
array=($string) # invoke the split+glob operator
for i in "${array[@]}"; do # loop over the array elements.
Aby zobaczyć różnicę między separatorem a separatorem , spróbuj:
string='var1_var2_'
To będzie podzielić ją na var1
i var2
tylko (bez dodatkowych pusty element).
Aby więc był podobny do skryptów JavaScript split()
, potrzebujesz dodatkowego kroku:
string='var1_var2_var3'
IFS=_ # delimit on _
set -f # disable the glob part
temp=${string}_ # add an extra delimiter
array=($temp) # invoke the split+glob operator
(zwróć uwagę, że podzieliłby pusty element $string
na 1 (nie 0 ), jak JavaScript split()
).
Aby zobaczyć kartę specjalnych zabiegów, spację i znak nowej linii, porównaj:
IFS=' '; string=' var1 var2 '
(skąd bierzesz var1
i var2
) z
IFS='_'; string='_var1__var2__'
gdzie można uzyskać: ''
, var1
, ''
, var2
, ''
.
Zauważ, że zsh
powłoka nie wywołuje tego operatora split + glob domyślnie w ten sposób, chyba że w sh
lub ksh
emulacji. Tam musisz je bezpośrednio przywołać. $=string
dla części podzielonej, $~string
dla części globalnej ( $=~string
dla obu), a także ma operator podziału, w którym można określić separator:
array=(${(s:_:)string})
lub w celu zachowania pustych elementów:
array=("${(@s:_:)string}")
Należy zauważyć, że nie s
jest do rozszczepiania , nie ograniczające (również $IFS
, znany POSIX niezgodności z zsh
). Różni się od skryptów JavaScript tym, split()
że pusty ciąg jest podzielony na element 0 (nie 1).
Godnym Różnica $IFS
-splitting jest to, że ${(s:abc:)string}
podziały na abc
struny, natomiast z IFS=abc
, które podzielone na a
, b
lub c
.
Za pomocą zsh
i ksh93
, specjalne traktowanie, które otrzymują spacja, tabulator lub znak nowej linii, można usunąć, podwajając je $IFS
.
Historycznie rzecz biorąc, powłoka Bourne'a (przodek lub współczesne pociski POSIX) zawsze usuwała puste elementy. Miał także szereg błędów związanych z dzieleniem i rozszerzaniem $ @ o wartościach innych niż default $IFS
. Na przykład IFS=_; set -f; set -- $@
nie byłoby równoważne z IFS=_; set -f; set -- $1 $2 $3...
.
Dzielenie wyrażeń regularnych
Teraz, aby znaleźć coś bliższego JavaScript'owi, split()
który może dzielić się na wyrażenia regularne, musisz polegać na zewnętrznych narzędziach.
W skrzynce narzędzi POSIX awk
ma split
operator, który może dzielić rozszerzone wyrażenia regularne (są one mniej więcej podzbiorem wyrażeń regularnych podobnych do Perla obsługiwanych przez JavaScript).
split() {
awk -v q="'" '
function quote(s) {
gsub(q, q "\\" q q, s)
return q s q
}
BEGIN {
n = split(ARGV[1], a, ARGV[2])
for (i = 1; i <= n; i++) printf " %s", quote(a[i])
exit
}' "$@"
}
string=a__b_+c
eval "array=($(split "$string" '[_+]+'))"
zsh
Powłoka posiada wbudowane wsparcie dla kompatybilnych Perl wyrażeń regularnych (w jego zsh/pcre
moduł), ale przy użyciu go podzielić ciąg, choć możliwe jest stosunkowo kłopotliwe.
shell
używasz, zbash
czym możesz zrobićIFS='_' read -a array <<< "${string}"