Dividir uma única string no array de caracteres usando ONLY bash

7

Eu quero dividir 'hello' em h e l l o em uma matriz usando apenas bash, eu poderia fazê-lo em sed com sed 's/./& /g' , mas eu quero saber como dividir uma string em uma matriz no Bash quando eu não saber o que o delimitador seria ou o delimitador é qualquer caractere único. Eu não acho que eu posso usar ${i// /} sem alguma criatividade porque o delimitador é um desconhecido, e eu não acho que essa expressão aceita regex. Eu tentei usar BASH_REMATCH com [[string = ~ ([a-z].).]] Mas não funciona como eu esperava. Qual é a maneira correta de usar apenas bash para realizar um tipo de comportamento string.split() ? O motivo é que estou tentando gravar o utilitário rev em todo o bash:

  while read data; do
  word=($(echo $data|tr ' ' '_'|sed 's/./& /g'))
  new=()
  i=$((${#word[@]} - 1))
  while [[ $i -ge 0 ]]; do
    new+=(${word[$i]})
    (( i-- ))
  done
  echo ${new[@]}|tr -d ' '|tr '_' ' '
  done

Mas eu usei tr e sed, eu quero saber como fazer o split corretamente e então eu vou consertar isso para ser todo o bash. Apenas por diversão.

    
por Gregg Leventhal 19.04.2015 / 17:56

4 respostas

9
s="hello"
declare -a a
for ((i=0; i<${#s}; i++)); do a[$i]="${s:$i:1}"; done
declare -p a

Saída:

declare -a a='([0]="h" [1]="e" [2]="l" [3]="l" [4]="o")'

ou

s="hello"
while read -n 1 c; do a+=($c); done  <<< "$s"
declare -p a

Saída:

declare -a a='([0]="h" [1]="e" [2]="l" [3]="l" [4]="o")'
    
por 19.04.2015 / 18:25
2

Para dividir uma string em uma matriz de caracteres, com um delimitador nulo, você pode:

str='hello'
arr=()
i=0
while [ "$i" -lt "${#str}" ]; do
  arr+=("${str:$i:1}")
  i=$((i+1))
done

printf '%s\n' "${arr[@]}"

Com um delimitador diferente de nulo, você pode:

set -f
str='1,2,3,4,5'
IFS=',' arr=($str)
printf '%s\n' "${arr[@]}"
    
por 19.04.2015 / 18:32
1

Apenas por diversão (e outras shells) outra variante:

word=hello
unset letter
while [ ${#word} -gt 0 ]
do
    rest=${word#?}
    letter[${#letter[*]}]=${word%$rest}
    word=$rest
done

E verifique

for l in "${!letter[@]}"
do
    echo "letter [$l] = ${letter[l]}"
done

imprimirá

letter [0] = h
letter [1] = e
letter [2] = l
letter [3] = l
letter [4] = o
    
por 19.04.2015 / 20:27
0

Método 1:

Oneliner:

s="hello"
for ((i=0;i<${#s};i++)); do result[$i]="${s:i:1}"; done
echo ${result[@]}

Código expandido:

s="hello"                   # Original string.

for ((i=0;i<${#s};i++)); do # For i=0; i<(length of s); i++
    result[$i]="${s:i:1}"       # result[i] is equal to the i th character of $s
done                        # End of the loop

echo ${result[@]} # Print all elements of $result.

Método 2:

Oneliner:

s="hello"
var=($(while read -n 1; do printf "$REPLY "; done <<< "$s"))
echo "${var[@]}"

Código expandido:

s="hello" # Original string.

while read -n 1; do # Read chraracter by character the string.
    space_separated=$(printf "$space_separated $REPLY") # $space_separated is equal to it plus the current character.
done <<< "$s" # Pass the string to the loop

result=($space_separated) # Split $space_separated into an array.

echo "${result[@]}" # Print all elements of $result.

Agradecemos a @cuonglm por sua sugestão.
Efetivamente, você pode usar $REPLY , que é o padrão onde read lê a entrada.

    
por 19.04.2015 / 18:54