Расщепление строки по первому вхождению разделителя

54

У меня есть строка в следующем формате

id;some text here with possible ; inside

и хочу разделить его на 2 строки по первому появлению ;. Итак, должно быть: idиsome text here with possible ; inside

Я знаю, как разбить строку (например, с помощью cut -d ';' -f1), но она будет разбита на несколько частей, так как у меня ;внутри левая часть.

Гахов
источник
После того, как строка разбита, что вы хотите сделать с "id"? Вы хотите присвоить его переменной, распечатать и т. Д.?
Демон Хаоса
У меня будет 2 переменные: idаstring
Гахов

Ответы:

65

cut звучит как подходящий инструмент для этого:

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

Но readеще более подходит:

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
manatwork
источник
3
Большой! Отлично работает! Я выберу, readтак как я использую bash. Спасибо @manatwork!
Гахов
cutПодход будет работать только когда «$ s» не содержит символов новой строки. читать можно в любой борноподобной оболочке. <<< находится в rc, zsh и последних версиях bash и ksh93 и является нестандартной.
Стефан Шазелас
К сожалению, вы правы @StephaneChazelas. Мой разум был -aпо какой-то причине, когда упоминал bashо read. (Очевидно, здесь бесполезно.)
manatwork
Я забыл упомянуть, что подход чтения не работает, если $ s также содержит символы новой строки. Я добавил свой ответ.
Стефан Шазелас
1
Я хотел бы подчеркнуть , косую черту в -f 2-в string="$( cut -d ';' -f 2- <<< "$s" )"; echo "$string"команде. Это то, что игнорирует остальные разделители в строке для распечатки. Не очевидно при взгляде на справочную страницуcut
Steen
18

С любым стандартным sh (включая bash):

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

readоснованные решения будут работать для односимвольных (и с некоторыми оболочками, однобайтовыми) значений, $sepотличных от пробела, табуляции или новой строки, и только если $sони не содержат символов новой строки.

cutоснованные решения будут работать, только если $sне содержат символов новой строки.

sedМогут быть разработаны решения, которые обрабатывают все угловые случаи с любым значением $sep, но не стоит заходить так далеко, когда для этого есть встроенная поддержка в оболочке.

Стефан Шазелас
источник
6

Как вы упомянули, вы хотите присвоить значения идентификатору и строке

сначала присвойте свой шаблон переменной (скажем, str)

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

Теперь у вас есть значения в соответствующих переменных

user1678213
источник
если вы получаете свой шаблон из команды, тогда используйте set - some_command, тогда ваш шаблон будет храниться в $ 1 и использовать вышеуказанный код с 1 вместо str
user1678213
1
Чем этот ответ отличается от @StephaneChazelas?
Бернхард
4

В дополнение к другим решениям, вы можете попробовать что-то на regexоснове:

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

или в зависимости от того, что вы пытаетесь сделать точно, вы можете использовать

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

где \1и \2содержат две подстроки, которые вы хотели.

tojrobinson
источник
1

Решение в стандартном bash:

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

    echo $text1
    #=> id;
    echo $text2
    #=> some text here with possible ; insideDD
ethaning
источник