W split()
JavaScripcie bardzo łatwo jest podzielić łańcuch na tablicę.
Co ze skryptem powłoki?
Powiedz, że chcę to zrobić:
$ script.sh var1_var2_var3
Gdy użytkownik poda taki ciąg var1_var2_var3
do script.sh, wewnątrz skryptu przekształci ciąg w podobną tablicę
array=( var1 var2 var3 )
for name in ${array[@]}; do
# some code
done
shell
shell-script
string
AGamePlayer
źródło
źródło
shell
używasz, zbash
czym możesz zrobićIFS='_' read -a array <<< "${string}"
perl
też mogę to zrobić. To nie jest „czysta” powłoka, ale jest dość powszechna.Odpowiedzi:
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[@]}
zamiastfor 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
_
:Aby zobaczyć różnicę między separatorem a separatorem , spróbuj:
To będzie podzielić ją na
var1
ivar2
tylko (bez dodatkowych pusty element).Aby więc był podobny do skryptów JavaScript
split()
, potrzebujesz dodatkowego kroku:(zwróć uwagę, że podzieliłby pusty element
$string
na 1 (nie 0 ), jak JavaScriptsplit()
).Aby zobaczyć kartę specjalnych zabiegów, spację i znak nowej linii, porównaj:
(skąd bierzesz
var1
ivar2
) zgdzie 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 wsh
lubksh
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:lub w celu zachowania pustych elementów:
Należy zauważyć, że nie
s
jest do rozszczepiania , nie ograniczające (również$IFS
, znany POSIX niezgodności zzsh
). 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 naabc
struny, natomiast zIFS=abc
, które podzielone naa
,b
lubc
.Za pomocą
zsh
iksh93
, 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ładIFS=_; set -f; set -- $@
nie byłoby równoważne zIFS=_; 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
masplit
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).zsh
Powłoka posiada wbudowane wsparcie dla kompatybilnych Perl wyrażeń regularnych (w jegozsh/pcre
moduł), ale przy użyciu go podzielić ciąg, choć możliwe jest stosunkowo kłopotliwe.źródło
$PATH
na:
) Wręcz przeciwnie, na ogół chcą zachować pustych elementów. Zauważ, że w powłoce Bourne'a wszystkie postacie otrzymywały specjalne traktowanie,ksh
zmieniono tak, aby traktować tylko puste (tylko spację, tabulator i znak nowej linii) specjalnie.zsh
leczenia ciągiem zawierającym 2 lub więcej znaków w${(s:string:)var}
? JeśliS
oznacza Separator , a nie ogranicznik . Przynajmniej tak mówi instrukcja mojej bash.$IFS
pochodzi z powłoki Bourne'a, w której był separatorem , ksh zmienił zachowanie bez zmiany nazwy. Wspominam o tym, aby podkreślić, żesplit+glob
(z wyjątkiem zsh lub pdksh) nie dzieli się już po prostu.Tak, użyj
IFS
i ustaw na_
. Następnie użyjread -a
do zapisania w tablicy (-r
wyłącza rozwinięcie odwrotnego ukośnika). Zauważ, że jest to specyficzne dla bash; ksh i zsh mają podobne funkcje z nieco inną składnią, a zwykły sh w ogóle nie ma zmiennych tablicowych.Od
man bash
:Zauważ, że
read
zatrzymuje się przy pierwszej nowej linii. Przejdź,-d ''
abyread
tego uniknąć, ale w takim przypadku na końcu pojawi się dodatkowa nowa linia ze względu na<<<
operatora. Możesz go usunąć ręcznie:źródło
$r
że nie zawiera znaków nowej linii ani odwrotnych ukośników. Zauważ też, że będzie działać tylko w najnowszych wersjachbash
powłoki.bash
,read -a
został wprowadzony w bash 4, prawda?<<<
został dodany dopiero niedawno,bash
ale wygląda na to, że był tam od 2.05b (2002).read -a
jest jeszcze starszy.<<<
pochodzi zzsh
i jest obsługiwany przezksh93
(oraz mksh i yash), aleread -a
jest specyficzny dla bash (jest-A
w ksh93, yash i zsh).