exemplo a seguir:
string=" 'f o o' 'f oo' 'fo o' "
array=($string)
echo "${array[0]}"
saídas:
'f
enquanto a saída esperada é:
'f o o'
A única solução que encontrei foi alterar o delimitador para nova linha (em vez de espaço):
IFS=$'\n'
string="'f o o' # 'f oo' # 'fo o' #"
array=($(echo "$string" | tr '#' '\n'))
echo "${array[0]}"
saídas:
'f o o'
que produz o resultado esperado, no entanto, isso requer definir um delimitador personalizado em string e invocará um novo subprocesso em cada chamada. Gostaria de ver uma solução melhor do que essa, obrigado!
Editar:
A string de exemplo acima deve ser suficiente, mas como alguns perguntaram como é o conteúdo do arquivo, é algo parecido com isto:
'magic1' 'some text' 'another simple text' 'some t£xt'
'magic2' 'another line with simple text' 'foo bar' 'yeah another substring'
'magic3' 'so@m{e$%& te+=*&' 'another substring' 'here is the substring'
'magic4' 'why not another line !' 'yeah I like that' 'the substring yeah !!!'
Ainda mais detalhes (como alguns usuários solicitaram): há uma função personalizada que grep
retorna a linha do arquivo acima usando um substring
.
por exemplo, minha função find é semelhante a esta:
_find()
{
string="$(grep "$1" "$file")"
}
então eu chamo assim:
_find "magic2"
echo "$string"
que produz:
'magic2' 'another line with simple text' 'foo bar' 'yeah another substring'
P/S: cada substring é delimitada por espaço, e cada substring é citada entre aspas simples. _find
Não é possível editá-la, pois ela é usada por outras funções. Veja os comentários para mais informações.
Se a entrada for tão simples quanto mostrada na pergunta e você realmente quiser evitar a geração de um subshell em cada invocação, como você declarou:
então você poderia usar um loop isolando cada
'...'
substring e armazenando-a em uma matriz:Se você não se importar com um subshell, você pode usar o GNU grep para
-o
apenas imprimir as substrings entre aspas simples e então lê-las em um array:ou se você não tiver um grep que suporte isso,
-o
você pode usar qualquer sed para remover espaços em branco iniciais/finais e alterar tudo' '
para'<newline>'
então ler o resultado em uma matriz:Se você quiser se livrar do
'
s do resultado, basta alterar osed
comando parased -E "s/^ +'|' +$//g; s/' +'/\n/g"
.Se o objetivo é fazer a tokenização da sintaxe da linguagem shell, mas sem remover aspas e sem executar nenhum código, então você pode alternar para
zsh
o que tem operadores apenas para isso: oz
sinalizador de expansão de parâmetro e suaZ[tuning]
variante para personalizar o que acontece com relação a novas linhas e comentários.Com um exemplo mais complexo:
Com apenas
z
:A nova linha é tratada como delimitador de comando, assim como
;
(e tokenizada como;
) e#
não é tratada como introdutor de comentário.Com
Z[n]
, a nova linha sem aspas é tratada apenas como outro delimitador de token, como espaço ou tabulação.Com
c
,#
introduz um comentário, e os comentários compõem o token retornado.Com
C
, o mesmo, exceto que os comentários são removidos.Se você tiver que usar
bash
, já que o bash não pode armazenar NULs em suas variáveis de qualquer maneira, você pode fazer o bash obter o zsh para fazer a tokenização e imprimir o resultado delimitado por NUL, que o bash pode ler de volta em uma matrizreadarray -td ''
(assumindo o bash 4.4 ou mais recente):Ou se em um sistema com a implementação GNU
grep
com suporte para PCRE/PCRE2 habilitado, você poderia fazer um processamento de aspas simples, aspas duplas e barras invertidas semelhante ao feito por shells do tipo Bourne, como o bash, com:No exemplo "mais complexo" acima, isso dá:
Note que ele não faz tokenização de sintaxe de shell completa, apenas processa aspas. Veja como ele divide
$(echo foo bar)
, ele também dividiria$'foo\' bar'
or"$(echo '"' foo)"
.Para melhor portabilidade, você pode usar o perl (o
P
ingrep -P
) que, ao contrário do GNU,grep
deve ser instalado na maioria dos sistemas:O mais próximo que posso chegar é isso
Saída do seu exemplo simples
Especificamente para seu exemplo, observe que
"${a[0]}"
contém sete caracteres'f o o'
(incluindo as aspas)Saída do seu exemplo estendido
Você pode converter suas aspas simples em novas linhas para construir uma matriz:
Isso criará alguns elementos vazios que podem ou não ser um problema para você:
para que você possa removê-los:
Agora você ainda não tem suas aspas simples, que, como argumentei nos comentários, você provavelmente não precisa, por exemplo:
Observe como aspas simples armazenadas literalmente em uma variável não são as mesmas que aspas simples interpretadas pelo shell.
Entretanto, se você realmente quiser que eles voltem, você pode fazer isso (em vez do loop acima que só remove os elementos " "):