Divisão de sequência pela primeira ocorrência de um delimitador

54

Eu tenho uma string no próximo formato

id;some text here with possible ; inside

e deseja dividi-lo em 2 strings pela primeira ocorrência do ;. Então, deve ser: idesome text here with possible ; inside

Eu sei como dividir a string (por exemplo, com cut -d ';' -f1), mas ela será dividida em mais partes, já que tenho ;dentro da parte esquerda.

gakhov
fonte
Depois que a string é dividida, o que você quer fazer com o "id"? Deseja atribuí-lo a uma variável, imprimi-lo, etc?
Daemon of Chaos
Eu vou ter 2 variáveis: idestring
gakhov 30/10/12

Respostas:

65

cut soa como uma ferramenta adequada para isso:

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

Mas readé ainda mais adequado:

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
homem a trabalhar
fonte
3
Ótimo! Ele funciona como um encanto! Selecionarei o readque estou usando bash. Obrigado @manatwork!
gakhov
A cutabordagem só funcionará quando "$ s" não contiver caracteres de nova linha. read está em qualquer shell tipo Bourne. <<< está nas versões rc, zsh e recentes do bash e ksh93 e é o que não é padrão.
Stéphane Chazelas 30/10/12
Opa, você está certo @StephaneChazelas. Minha mente estava em -apor algum motivo ao mencionar bashé read. (Evidentemente não serve aqui.)
manatwork
Esqueci de mencionar que a abordagem de leitura não funciona se $ s contiver caracteres de nova linha. Eu adicionei minha própria resposta.
Stéphane Chazelas 30/10/12
11
Eu gostaria de enfatizar o traço à direita -f 2-no string="$( cut -d ';' -f 2- <<< "$s" )"; echo "$string"comando. Isso é o que ignora o restante dos delimitadores na sequência de caracteres para a impressão. Não é óbvio quando se olha para a página de manual decut
Steen
18

Com qualquer sh padrão (incluindo bash):

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

readas soluções baseadas funcionariam para valores de caractere único (e com alguns shells, byte único) $sepque não sejam espaço, tabulação ou nova linha e somente se $snão contiver caracteres de nova linha.

cutsoluções baseadas só funcionariam se $snão contiver caracteres de nova linha.

sedPoderiam ser criadas soluções para lidar com todos os casos de canto com qualquer valor de $sep, mas não vale a pena ir tão longe quando houver suporte embutido no shell para isso.

Stéphane Chazelas
fonte
6

Como você mencionou que deseja atribuir os valores a id e string

primeiro atribua seu padrão a uma variável (diga str)

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

Agora você tem seus valores nas respectivas variáveis

user1678213
fonte
se você está recebendo o seu padrão de um comando, em seguida, usar set - some_command, então o seu padrão ficarão armazenados no $ 1 e usar o código acima, com 1 em vez de str
user1678213
11
Qual é a diferença desta resposta para @StephaneChazelas?
31512 Bernhard
4

Além das outras soluções, você pode tentar algo com regexbase:

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

ou dependendo do que você está tentando fazer exatamente, você pode usar

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

onde \1e \2conter os dois substrings que você estava querendo.

tojrobinson
fonte
1

Solução no bash padrão:

    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
fonte