Dzielenie łańcucha według pierwszego wystąpienia separatora


54

Mam ciąg w następnym formacie

id;some text here with possible ; inside

i chcę podzielić go na 2 łańcuchy przez pierwsze wystąpienie ;. Tak powinno być: idisome text here with possible ; inside

Wiem, jak podzielić ciąg (na przykład za pomocą cut -d ';' -f1), ale zostanie on podzielony na więcej części, ponieważ mam ;wewnątrz lewej części.


Po podzieleniu łańcucha, co chcesz zrobić z „id”? Czy chcesz przypisać ją do zmiennej, wydrukować itp.?
Daemon of Chaos

Będę miał 2 zmienne: idistring
gakhov

Odpowiedzi:


65

cut brzmi jak odpowiednie narzędzie do tego:

bash-4.2$ s='id;some text here with possible ; inside'

bash-4.2$ id="$( cut -d ';' -f 1 <<< "$s" )"; echo "$id"
id

bash-4.2$ string="$( cut -d ';' -f 2- <<< "$s" )"; echo "$string"
some text here with possible ; inside

Ale readjest jeszcze bardziej odpowiedni:

bash-4.2$ IFS=';' read -r id string <<< "$s"

bash-4.2$ echo "$id"
id

bash-4.2$ echo "$string"
some text here with possible ; inside

3
Wspaniały! To działa jak urok! Wybiorę, readodkąd używam bash. Dziękuję @manatwork!
gakhov

cutPodejście będzie działać tylko wtedy, gdy „$ s” nie zawiera znaki nowej linii. read znajduje się w dowolnej powłoce podobnej do Bourne'a. <<< jest w rc, zsh i najnowszych wersjach bash i ksh93 i jest tym, który nie jest standardem.
Stéphane Chazelas

Ups, masz rację @StephaneChazelas. Mój umysł był na -ajakiegoś powodu, gdy wspomnieć bash„s read. (Widocznie bezużyteczne tutaj.)
Manatwork

Zapomniałem wspomnieć, że metoda odczytu nie działa, jeśli $ s zawiera również znaki nowej linii. Dodałem własną odpowiedź.
Stéphane Chazelas

1
Chciałbym podkreślić kreskę w spływu -f 2-w string="$( cut -d ';' -f 2- <<< "$s" )"; echo "$string"poleceniu. To ignoruje resztę ograniczników w ciągu wydruku. Nie jest to oczywiste, gdy patrzy się na stronę podręcznika użytkownikacut
Steen

17

Z dowolnym standardowym sh (w tym bash):

sep=';'
case $s in
  (*"$sep"*)
    before=${s%%"$sep"*}
    after=${s#*"$sep"}
    ;;
  (*)
    before=$s
    after=
    ;;
esac

readoparte na rozwiązaniach działałyby dla wartości pojedynczych znaków (a przy niektórych powłokach, jednobajtowych) wartości $sepinnych niż spacja, tabulator lub nowa linia i tylko wtedy, $sgdy nie zawiera znaków nowej linii.

cutoparte na rozwiązaniach działałyby tylko wtedy, gdyby $snie zawierały znaków nowej linii.

sedmożna opracować rozwiązania, które obsługują wszystkie przypadki narożne o dowolnej wartości $sep, ale nie warto posuwać się tak daleko, gdy wbudowane jest wsparcie dla powłoki.


6

Jak już wspomniałeś, chcesz przypisać wartości do identyfikatora i ciągu

najpierw przypisz wzór do zmiennej (powiedzmy str)

    str='id;some text here with possible ; inside'
    id=${str%%;} 
    string=${str#;}

Teraz masz swoje wartości w odpowiednich zmiennych


jeśli otrzymujesz swój wzorzec z polecenia, użyj set - some_command, wtedy wzorzec zostanie zapisany w 1 $ i użyje powyższego kodu z 1 zamiast str
user1678213

Czym różni się ta odpowiedź od @StephaneChazelas?
Bernhard

4

Oprócz innych rozwiązań możesz wypróbować coś regexopartego na:

a="$(sed 's/;.*//' <<< "$s")"
b="$(sed 's/^[^;]*;//' <<< "$s")"

lub w zależności od tego, co dokładnie próbujesz zrobić, możesz użyć

sed -r 's/^([^;]*);(.*)/\1 ADD THIS TEXT BETWEEN YOUR STRINGS \2/'

gdzie \1i \2zawierają dwa podciągi, których chciałeś.


1

Rozwiązanie w standardowym bashu:

    text='id;some text here with possible ; inside'
    text2=${text#*;}
    text1=${text%"$text2"}

    echo $text1
    #=> id;
    echo $text2
    #=> some text here with possible ; insideDD
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.