Mam ten ciąg przechowywany w zmiennej:
IN="[email protected];[email protected]"
Teraz chciałbym podzielić ciągi znaków według ;
ogranicznika, aby:
ADDR1="[email protected]"
ADDR2="[email protected]"
Niekoniecznie potrzebuję zmiennych ADDR1
i ADDR2
. Jeśli są to elementy tablicy, które są jeszcze lepsze.
Po sugestiach z poniższych odpowiedzi, skończyłem z następującymi, co było po:
#!/usr/bin/env bash
IN="[email protected];[email protected]"
mails=$(echo $IN | tr ";" "\n")
for addr in $mails
do
echo "> [$addr]"
done
Wynik:
> [bla@some.com]
> [john@home.com]
Było rozwiązanie polegające na ustawieniu Internal_field_separator (IFS) na ;
. Nie jestem pewien, co się stało z tą odpowiedzią, w jaki sposób przywracasz IFS
ustawienia domyślne?
RE: IFS
rozwiązanie, próbowałem tego i działa, zachowuję stary, IFS
a następnie przywracam:
IN="[email protected];[email protected]"
OIFS=$IFS
IFS=';'
mails2=$IN
for x in $mails2
do
echo "> [$x]"
done
IFS=$OIFS
BTW, kiedy próbowałem
mails2=($IN)
Pierwszy ciąg mam tylko podczas drukowania w pętli, ale bez nawiasów wokół $IN
niego działa.
local IFS=...
gdzie to możliwe; (b) -1unset IFS
, ponieważ nie resetuje to dokładnie IFS do wartości domyślnej, chociaż uważam, że nieuzbrojony IFS zachowuje się tak samo jak domyślna wartość IFS ($ '\ t \ n'), jednak wydaje się, że złym postępowaniem jest zakładaj na ślepo, że twój kod nigdy nie będzie wywoływany z IFS ustawionym na wartość niestandardową; (c) innym pomysłem jest wywołanie podpowłoki:(IFS=$custom; ...)
po wyjściu podpowłoki IFS powróci do pierwotnego stanu.ruby -e "puts ENV.fetch('PATH').split(':')"
. Jeśli chcesz pozostać czystym, bash nie pomoże, ale łatwiej jest używać dowolnego języka skryptowego z wbudowanym podziałem.for x in $(IFS=';';echo $IN); do echo "> [$x]"; done
\n
tylko na spację. Więc ostatnia linia jestmails=($(echo $IN | tr ";" " "))
. Teraz mogę sprawdzić elementymails
za pomocą notacji tablicowejmails[index]
lub po prostu iteracji w pętliOdpowiedzi:
Możesz ustawić zmienną wewnętrznego separatora pól (IFS), a następnie pozwolić jej przeanalizować w tablicy. Kiedy dzieje się tak w poleceniu, wówczas przypisanie do
IFS
ma miejsce tylko w środowisku (pojedynczym) tego poleceniaread
. Następnie analizuje dane wejściowe zgodnie zIFS
wartością zmiennej w tablicy, którą możemy następnie iterować.Spowoduje to przeanalizowanie jednego wiersza elementów oddzielonych przez
;
, popychając go do tablicy. Rzeczy do przetwarzania w całości$IN
, za każdym razem jeden wiersz danych wejściowych oddzielony;
:źródło
IFS
w tym samym wierszu, coread
bez średnika lub innego separatora, w przeciwieństwie do oddzielnego polecenia, obejmuje go tym poleceniem - dlatego zawsze jest „przywracane”; nie musisz nic robić ręcznie.$IN
. Błąd został naprawiony wbash
4.3.Zaczerpnięty z podzielonej tablicy skryptów powłoki Bash :
Wyjaśnienie:
Konstrukcja ta zastępuje wszystkie wystąpienia
';'
(początkowy//
środków globalny zastąpić) w ciąguIN
z' '
(pojedyncza spacja), a następnie interpretuje ciąg oddzielonych znakiem spacji jako tablica (to co otaczające nawiasy zrobić).Składnia zastosowana w nawiasach klamrowych w celu zastąpienia każdego
';'
znaku' '
znakiem nosi nazwę Rozszerzenie parametru .Istnieje kilka typowych błędów:
IFS=':'; arrIN=($IN); unset IFS;
IFS=$'\n'; arrIN=($IN); unset IFS;
źródło
IN="[email protected];[email protected];*;broken apart"
. W skrócie: to podejście się przerwie, jeśli twoje tokeny zawierają osadzone spacje i / lub znaki. tak się*
dzieje, że token pasuje do nazw plików w bieżącym folderze.;*;
, to*
zostanie rozwinięty do listy nazw plików w bieżącym katalogu. -1Jeśli nie masz nic przeciwko natychmiastowemu ich przetworzeniu, lubię to:
Możesz użyć tego rodzaju pętli do zainicjowania tablicy, ale prawdopodobnie jest to łatwiejszy sposób. Mam nadzieję, że to pomaga.
źródło
IN="[email protected];[email protected];*;broken apart"
. W skrócie: to podejście się przerwie, jeśli twoje tokeny zawierają osadzone spacje i / lub znaki. tak się*
dzieje, że token pasuje do nazw plików w bieżącym folderze.Kompatybilna odpowiedź
Można to zrobić na wiele różnych sposobów grzmotnąć.
Jednak ważne jest, aby najpierw zauważyć, że
bash
ma wiele specjalnych funkcji (tak zwanych baszizmów ), które nie będą działać w żadnej innejmuszla.W szczególności tablice , tablice asocjacyjne i podstawianie wzorców , które są używane w rozwiązaniach w tym poście, a także inne w wątku, są bashizmami i mogą nie działać pod innymi powłokami, z których korzysta wiele osób.
Na przykład: w moim Debian GNU / Linux jest standardowa powłoka o nazwiedziarskość; Znam wielu ludzi, którzy lubią używać innej powłoki o nazwieksh; i istnieje również specjalne narzędzie o nazwiebusybox z własnym tłumaczem powłoki (popiół).
Żądany ciąg
Ciąg do podzielenia w powyższym pytaniu to:
Użyję zmodyfikowanej wersji tego ciągu, aby upewnić się, że moje rozwiązanie jest odporne na ciągi zawierające białe znaki, które mogłyby uszkodzić inne rozwiązania:
Podziel ciąg na podstawie separatora w grzmotnąć (wersja> = 4.2)
W czystej postaci
bash
możemy utworzyć tablicę z elementami podzielonymi przez tymczasową wartość dla IFS ( separator pola wejściowego ). IFS wskazuje między innymi,bash
które znaki należy traktować jako ogranicznik między elementami podczas definiowania tablicy:W nowszych wersjach
bash
, poprzedzając polecenie z definicji zmienia IFS IFS dla tego polecenia tylko i resetuje go do poprzedniej wartości zaraz potem. Oznacza to, że możemy to zrobić w jednym wierszu:Widzimy, że ciąg
IN
został zapisany w tablicy o nazwiefields
podzielonej na średniki:(Możemy również wyświetlić zawartość tych zmiennych za pomocą
declare -p
:)Zauważ, że
read
jest to najszybszy sposób wykonania podziału, ponieważ nie ma wywoływanych widelców ani zasobów zewnętrznych.Po zdefiniowaniu tablicy możesz użyć prostej pętli do przetworzenia każdego pola (a raczej każdego elementu w tablicy, którą teraz zdefiniowałeś):
Lub możesz usunąć każde pole z tablicy po przetworzeniu przy użyciu metody przesunięcia , co lubię:
A jeśli chcesz po prostu wydrukować tablicę, nie musisz jej nawet zapętlać:
Aktualizacja: ostatnia grzmotnąć > = 4,4
W nowszych wersjach
bash
możesz także grać za pomocą poleceniamapfile
:Ta składnia chroni specjalne znaki, znaki nowej linii i puste pola!
Jeśli nie chcesz dołączać pustych pól, możesz wykonać następujące czynności:
Za pomocą
mapfile
można również pominąć deklarowanie tablicy i niejawnie „zapętlić” ograniczane elementy, wywołując funkcję na każdym:(Uwaga:
\0
na końcu łańcucha formatu jest bezużyteczne, jeśli nie obchodzi Cię puste pole na końcu łańcucha lub nie ma ich).Lub możesz użyć
<<<
, a w treści funkcji włącz trochę przetwarzania, aby usunąć nowy wiersz, który dodaje:Podziel ciąg na podstawie separatora w muszla
Jeśli nie możesz użyć
bash
lub chcesz napisać coś, co można wykorzystać w wielu różnych powłokach, często nie możesz użyć bashism - i obejmuje to tablice, których używaliśmy w powyższych rozwiązaniach.Nie musimy jednak używać tablic do zapętlania „elementów” łańcucha. W wielu powłokach stosowana jest składnia do usuwania podciągów ciągu od pierwszego lub ostatniego wystąpienia wzorca. Pamiętaj, że
*
jest to symbol wieloznaczny oznaczający zero lub więcej znaków:(Brak tego podejścia w jakimkolwiek opublikowanym rozwiązaniu jest głównym powodem, dla którego piszę tę odpowiedź;)
Jak wyjaśniono w Score_Under :
Korzystając z powyższej składni, możemy stworzyć podejście, w którym wyodrębniamy „elementy” podłańcucha z ciągu, usuwając podciągi do separatora lub po nim.
Poniższy blok kodu działa dobrze w grzmotnąć(w tym Mac OS
bash
),dziarskość, ksh, i busybox„s popiół:Baw się dobrze!
źródło
#
,##
,%
i%%
substytucje mają co IMO jest łatwiejszy do zapamiętania wyjaśnienie (na ile kasować)#
i%
usunąć najkrótszy ciąg pasujący, a##
i%%
usunąć najdłużej to możliwe.IFS=\; read -a fields <<<"$var"
Nie działa na nowej linii i dodanie nowej linii spływu. Drugie rozwiązanie usuwa końcowe puste pole.for sep in "#" "ł" "@" ; do ... var="${var#*$sep}" ...
Widziałem kilka odpowiedzi dotyczących
cut
polecenia, ale wszystkie zostały usunięte. To trochę dziwne, że nikt o tym nie rozwinął, ponieważ uważam, że jest to jedno z bardziej użytecznych poleceń do robienia tego typu rzeczy, szczególnie do analizowania plików dziennika z ogranicznikami.W przypadku podzielenia tego konkretnego przykładu na tablicę skryptów bash,
tr
jest prawdopodobnie bardziej wydajny, alecut
można go użyć i jest bardziej skuteczny, jeśli chcesz wyciągnąć określone pola ze środka.Przykład:
Możesz oczywiście umieścić to w pętli i iterować parametr -f, aby pobrać każde pole niezależnie.
Staje się to bardziej przydatne, gdy masz plik dziennika z ogranicznikami taki jak ten:
cut
jest bardzo przydatne, aby móccat
ten plik i wybrać konkretne pole do dalszego przetwarzania.źródło
cut
, to odpowiednie narzędzie do pracy! Znacznie wyczyszczone niż jakikolwiek z tych hakerskich pocisków.To działało dla mnie:
źródło
Co powiesz na to podejście:
Źródło
źródło
IFS";" && Array=($IN)
$'...'
:IN=$'[email protected];[email protected];bet <d@\ns* kl.com>'
. Następnieecho "${Array[2]}"
wydrukuje ciąg z nową linią.set -- "$IN"
jest również konieczne w tym przypadku. Tak, aby zapobiec globalnej ekspansji, rozwiązanie powinno obejmowaćset -f
.Myślę, że AWK to najlepsze i skuteczne polecenie do rozwiązania twojego problemu. AWK jest domyślnie dołączany do prawie każdej dystrybucji Linuksa.
da
Oczywiście możesz zapisać każdy adres e-mail, zmieniając pole drukowania awk.
źródło
inode=
na,;
na przykładsed -i 's/inode\=/\;/g' your_file_to_process
, a następnie zdefiniować,-F';'
kiedy zastosujeszawk
, mam nadzieję, że może ci to pomóc.źródło
IN="this is first line; this is second line" arrIN=( $( echo "$IN" | sed -e 's/;/\n/g' ) )
wytworzy tablicę 8 elementów w tym przypadku (element dla każdej oddzielonej przestrzeni słów), a nie 2 (element dla każdej linii oddzielonej średnikiem dwukropka)arrIN=( $( echo "$IN" | sed -e 's/;/\n/g' ) )
do osiągnięcia, i porady, aby zmienić IFSIFS=$'\n'
na tych, którzy wylądują tutaj w przyszłości i muszą podzielić ciąg zawierający spacje. (i przywrócić go później). :)Działa to również:
Uważaj, to rozwiązanie nie zawsze jest poprawne. Jeśli przekażesz tylko „[email protected]”, przypisze to zarówno do ADD1, jak i ADD2.
źródło
Inne podejście do odpowiedzi Darrona , oto jak to robię:
źródło
IFS=";"
przypisanie istnieje tylko w$(...; echo $IN)
podpowłoce; dlatego niektórzy czytelnicy (w tym ja) początkowo myślą, że to nie zadziała. Założyłem, że wszystkie dolary $ IN zostały zalane przez ADDR1. Ale nickjb ma rację; to działa. Powodem jest to, żeecho $IN
polecenie analizuje argumenty przy użyciu bieżącej wartości $ IFS, ale następnie powtarza je na standardowe wyjście przy użyciu separatora spacji, niezależnie od ustawienia $ IFS. Zatem efekt netto jest taki, jakby ktoś go wywołałread ADDR1 ADDR2 <<< "[email protected] [email protected]"
(zwróć uwagę, że dane wejściowe nie są oddzielone spacją; -separated).*
wecho $IN
z nienotowanego ekspansji zmiennej.W Bash: kuloodporny sposób, który zadziała, nawet jeśli twoja zmienna zawiera nowe linie:
Popatrz:
Sztuczka, aby to zadziałało, polega na użyciu
-d
opcjiread
(separatora) z pustym separatorem, abyread
zmuszony był odczytać wszystko, co jest zasilane. I karmimyread
się dokładnie zawartością zmiennejin
, dzięki czemu nie ma końca nowej liniiprintf
. Pamiętaj, że umieszczamy również ogranicznik,printf
aby upewnić się, że przekazywany ciągread
ma ogranicznik końcowy. Bez niegoread
przycinałoby potencjalne końcowe pola puste:końcowe puste pole zostaje zachowane.
Aktualizacja dla Bash ≥4.4
Od wersji Bash 4.4 wbudowane
mapfile
(akareadarray
) obsługuje-d
opcję określania separatora. Stąd innym kanonicznym sposobem jest:źródło
\n
spacjami i*
jednocześnie. Również brak pętli; zmienna tablicowa jest dostępna w powłoce po wykonaniu (w przeciwieństwie do najwyższej pozytywnej odpowiedzi). Uwaga:in=$'...'
nie działa z podwójnymi cudzysłowami. Myślę, że potrzebuje więcej pozytywnych opinii.Co powiesz na ten jeden liniowiec, jeśli nie używasz tablic:
źródło
read -r ...
aby na przykład upewnić się, że dwa znaki „\ t” na wejściu kończą się tymi samymi dwoma znakami w zmiennych (zamiast pojedynczego znaku tabulacji).echo "ADDR1 $ADDR1"\n echo "ADDR2 $ADDR2"
do fragmentu spowoduje wyjścieADDR1 [email protected] [email protected]\nADDR2
(\ n to nowy wiersz)IFS
i tutaj ciągi, które zostało naprawione wbash
4.3. Cytowanie$IN
powinno to naprawić. (Teoretycznie$IN
nie podlega podziałowi ani globowaniu po rozwinięciu, co oznacza, że cytaty powinny być niepotrzebne. Jednak nawet w wersji 4.3 pozostała przynajmniej jedna usterka - zgłoszona i zaplanowana do usunięcia - więc cytowanie pozostaje dobre pomysł.)Bez ustawiania IFS
Jeśli masz tylko jeden dwukropek, możesz to zrobić:
dostaniesz:
źródło
Oto czysty 3-liniowy:
gdzie
IFS
rozgraniczaj słowa na podstawie separatora i()
służy do tworzenia tablicy . Następnie[@]
służy do zwracania każdego elementu jako osobnego słowa.Jeśli masz później kod, musisz również przywrócić
$IFS
, npunset IFS
.źródło
$in
cudzysłowu pozwala na rozszerzenie symboli wieloznacznych.Następująca funkcja Bash / zsh dzieli swój pierwszy argument na separator podany przez drugi argument:
Na przykład polecenie
daje
Dane wyjściowe mogą być na przykład przesyłane potokowo do innych poleceń. Przykład:
W porównaniu z innymi podanymi rozwiązaniami, to ma następujące zalety:
IFS
nie jest zastępowane: Z powodu dynamicznego określania zasięgu nawet zmiennych lokalnych, zastąpienieIFS
w pętli powoduje wyciek nowej wartości do wywołań funkcji wykonywanych z poziomu pętli.Tablice nie są używane: wczytywanie ciągu do tablicy przy użyciu
read
wymaga flagi-a
w Bash i-A
w zsh.W razie potrzeby funkcję można umieścić w skrypcie w następujący sposób:
źródło
help read
:-d delim continue until the first character of DELIM is read, rather than newline
możesz zastosować awk w wielu sytuacjach
możesz także tego użyć
źródło
Istnieje prosty i sprytny sposób:
Ale musisz użyć gnu xargs, BSD xargs nie może obsługiwać -d delim. Jeśli używasz Apple Mac jak ja. Możesz zainstalować gnu xargs:
następnie
źródło
To najprostszy sposób na zrobienie tego.
źródło
Jest tu kilka fajnych odpowiedzi (errator esp.), Ale dla czegoś analogicznego do podzielenia się na inne języki - to właśnie rozumiałem pierwotne pytanie - postanowiłem:
Teraz
${a[0]}
,${a[1]}
itp, to jak można by oczekiwać. Użyj${#a[*]}
dla wielu terminów. Lub w celu iteracji, oczywiście:WAŻNA UWAGA:
Działa to w przypadkach, gdy nie ma się o co martwić, co rozwiązało mój problem, ale może nie rozwiązać twojego.
$IFS
W takim przypadku skorzystaj z rozwiązania (rozwiązań).źródło
IN
zawiera więcej niż dwa adresy e-mail. Proszę odnieść się do tego samego pomysłu (ale naprawionego) w odpowiedzi palindromu${IN//;/ }
(podwójny ukośnik), aby działało również z więcej niż dwiema wartościami. Uwaga: wszelkie symbole wieloznaczne (*?[
) zostaną rozwinięte. I końcowe puste pole zostanie odrzucone.Wynik
System: Ubuntu 12.04.1
źródło
read
tutaj i dlatego może zdenerwować resztę kodu, jeśli taki istnieje.Jeśli nie ma miejsca, dlaczego nie to?
źródło
Użyj
set
wbudowanego, aby załadować$@
tablicę:Następnie zacznij przyjęcie:
źródło
set -- $IN
aby uniknąć problemów z „$ IN” zaczynających się od myślnika. Mimo to niecytowane rozwinięcie$IN
spowoduje rozwinięcie symboli wieloznacznych (*?[
).Dwie alternatywne opcje, w których żadna nie wymaga tablic bash:
Przypadek 1 : Zachowaj prostotę i prostotę: użyj NewLine jako separatora rekordów ... np.
Uwaga: w tym pierwszym przypadku żaden podproces nie jest rozwidlany, aby pomóc w manipulowaniu listami.
Pomysł: Być może warto intensywnie stosować NL wewnętrznie , a konwersję do innego RS można generować tylko zewnętrznie .
Przypadek 2 : Używanie „;” jako separator rekordów ... np.
W obu przypadkach można utworzyć podlistę w pętli, która jest trwała po zakończeniu pętli. Jest to przydatne podczas manipulowania listami w pamięci zamiast przechowywania list w plikach. {ps zachowaj spokój i kontynuuj B-)}
źródło
Oprócz fantastycznych odpowiedzi, które już zostały udzielone, jeśli chodzi tylko o wydrukowanie danych, które możesz rozważyć przy użyciu
awk
:Spowoduje to ustawienie separatora pól na
;
, aby mógł on zapętlać pola za pomocąfor
pętli i odpowiednio drukować.Test
Z innym wejściem:
źródło
W powłoce Androida większość proponowanych metod po prostu nie działa:
Co działa to:
gdzie
//
oznacza globalną wymianę.źródło
Wynik:
Objaśnienie: Proste przypisanie za pomocą nawiasu () przekształca listę oddzieloną średnikami w tablicę, pod warunkiem, że podczas wykonywania tej operacji masz poprawny IFS. Standardowa pętla FOR obsługuje poszczególne elementy w tej tablicy jak zwykle. Zauważ, że lista podana dla zmiennej IN musi być „twarda”, tzn. Z pojedynczymi tikami.
IFS musi zostać zapisany i przywrócony, ponieważ Bash nie traktuje przypisania w taki sam sposób jak polecenia. Alternatywnym obejściem jest zawinięcie przypisania do funkcji i wywołanie tej funkcji za pomocą zmodyfikowanego IFS. W takim przypadku oddzielne zapisywanie / przywracanie IFS nie jest potrzebne. Dzięki za „Bize” za zwrócenie na to uwagi.
źródło
!"#$%&/()[]{}*? are no problem
cóż ... niezupełnie:[]*?
są postaciami globalnymi. A co z utworzeniem tego katalogu i pliku: `mkdir '!" # $% &'; Touch '! "# $% & / () [] {} Dostałeś hahahaha - nie ma problemu' i uruchomiłeś polecenie? proste może być piękne, ale kiedy jest zepsute, jest zepsute.mkdir '!"#$%&'; touch '!"#$%&/()[]{} got you hahahaha - are no problem'
. Muszą przyznać, że stworzą tylko katalog i plik o dziwnie wyglądających nazwach. Następnie uruchom komendy z dokładnymIN
daliście:IN='[email protected];[email protected];Charlie Brown <[email protected];!"#$%&/()[]{}*? are no problem;simple is beautiful :-)'
. Zobaczysz, że nie uzyskasz oczekiwanych wyników. Ponieważ używasz metody podlegającej rozszerzeniom nazw ścieżek, aby podzielić ciąg.*
,?
,[...]
a nawet, jeśliextglob
jest ustawiona,!(...)
,@(...)
,?(...)
,+(...)
są problemy z tej metody!Okej chłopaki!
Oto moja odpowiedź!
Dlaczego takie podejście jest dla mnie „najlepsze”?
Z dwóch powodów:
[]
źródło
/etc/os-release
i/etc/lsb-release
mają być pozyskiwane, a nie analizowane. Więc twoja metoda jest naprawdę zła. Co więcej, nie do końca odpowiadasz na pytanie o spilt string w ograniczniku.Jednowarstwowy do dzielenia łańcucha rozdzielonego znakiem „;” w tablicę jest:
To tylko ustawia IFS w podpowłoce, więc nie musisz się martwić o zapisywanie i przywracanie jego wartości.
źródło
0: [email protected];[email protected]\n 1:
(\ n to nowa linia)$IN
jest cytowany, więc nie podlega podziałowi IFS. 3. Podstawienie procesu jest podzielone na białe znaki, ale może to uszkodzić oryginalne dane.Może nie jest to najbardziej eleganckie rozwiązanie, ale działa z
*
i spacjami:Wyjścia
Inny przykład (ograniczniki na początku i na końcu):
Zasadniczo usuwa każdą postać inną niż
;
tworzeniedelims
np.;;;
. Następnie wykonujefor
pętlę od1
do,number-of-delimiters
zgodnie z obliczeniami${#delims}
. Ostatnim krokiem jest bezpieczne zdobycie$i
tej częścicut
.źródło