Eu escrevi um exemplo de script para dividir a string, mas não está funcionando conforme o esperado
#!/bin/bash
IN="One-XX-X-17.0.0"
IFS='-' read -r -a ADDR <<< "$IN"
for i in "${ADDR[@]}"; do
echo "Element:$i"
done
#split 17.0.0 into NUM
IFS='.' read -a array <<<${ADDR[3]};
for element in "${array[@]}"
do
echo "Num:$element"
done
resultado
One
XX
X
17.0.0
17 0 0
mas eu esperava que a saída fosse:
One
XX
X
17.0.0
17
0
0
bash
shell-script
lfs
user112232
fonte
fonte
Respostas:
Correção (veja também a resposta de S. Chazelas para obter informações detalhadas ), com saída sensível:
Resultado:
Notas:
É melhor colocar o condicional 2º ciclo no 1º ciclo.
bash
substituição de padrão ("${i//.}"
) verifica se existe.
um elemento. (Umacase
declaração pode ser mais simples, embora menos semelhante ao código do OP .)read
ing$array
introduzindo<<< "${ADDR[3]}"
é menos do que geral<<< "$i"
. Evita a necessidade de saber qual elemento possui os.
s.O código pressupõe que a impressão " Elemento: 17.0.0 " não é intencional. Se esse comportamento for intencional, substitua o loop principal por:
fonte
case $i in (*.*) ...
seria uma maneira mais canônica de verificar se$i
contém.
(e também é portátil parash
). Se você gosta de kismo, veja também:[[ $i = *.* ]]
case
nas notas no final, mas concordamos. (Uma vez que o OP usa tanto<<<
e matrizes , isso não é muito de umash
questão.)Nas versões antigas,
bash
você tinha que citar variáveis depois<<<
. Isso foi corrigido no 4.4. Nas versões anteriores, a variável seria dividida no IFS e as palavras resultantes unidas no espaço antes de serem armazenadas no arquivo temporário que compõe esse<<<
redirecionamento.No 4.2 e antes, ao redirecionar os componentes internos como
read
oucommand
, essa divisão levaria o IFS para o componente interno (4.3 corrigiu isso):Essa foi corrigida em 4.3:
Mas
$a
ainda está sujeito à divisão de palavras por lá:No 4.4:
Para portabilidade para versões mais antigas, cite sua variável (ou use de
zsh
onde ela<<<
vem em primeiro lugar e que não possui esse problema)Observe que essa abordagem para dividir uma string funciona apenas para strings que não contêm caracteres de nova linha. Observe também que
a..b.c.
seria dividida em"a"
,""
,"b"
,"c"
(sem esvaziar último elemento).Para dividir seqüências arbitrárias, você pode usar o operador split + glob (o que a tornaria padrão e evitaria armazenar o conteúdo de uma variável em um arquivo temporário da mesma
<<<
forma):ou:
O
''
objetivo é preservar um elemento vazio à direita, se houver. Isso também dividiria um vazio$var
em um elemento vazio.Ou use um shell com um operador de divisão adequado:
zsh
:rc
:fish
fonte
Com o awk , custaria uma linha:
-F'[-.]'
- separador de campos com base em vários caracteres, no nosso caso-
e.
A saída:
fonte
IFS=-. read -r a array <<< "$IN"
Aqui do meu jeito:
resultado conforme o esperado:
fonte
$IN
está chamando o operador split + glob. Aqui, você não deseja a parte da glob (tenteIN=*-*-/*-17.0.0
por exemplo), por issoset -o noglob
antes de invocá-la. Veja minha resposta para detalhes.IFS
e configurá-lo globalmente. Você realmente deseja alterar apenas o valor deIFS
quando$IN
é expandido e também não deseja que a expansão do nome do caminho seja executada na expansão. Além disso,OIFS=$IFS
não faz distinção entre os casos quandoIFS
foi definido como uma sequência vazia e quandoIFS
estava completamente desmarcado.