Pisahkan string tunggal menjadi array karakter menggunakan HANYA bash

9

Saya ingin memecah 'hello'menjadi h e l l odalam array hanya menggunakan bash, saya bisa melakukannya dengan sed 's/./& /g'tetapi saya ingin tahu bagaimana membagi string ke dalam array di Bash ketika saya tidak tahu apa pembatas akan menjadi, atau pembatas adalah karakter tunggal. Saya tidak berpikir saya dapat menggunakan ${i// /}tanpa kreativitas karena pembatas adalah tidak diketahui, dan saya tidak berpikir bahwa ekspresi menerima regex. Saya mencoba menggunakan BASH_REMATCH dengan [[string = ~ ([az].). *]] Tetapi tidak berfungsi seperti yang saya harapkan. Apa cara yang tepat untuk menggunakan hanya bash untuk mencapai string.split()jenis perilaku? Alasannya adalah bahwa saya mencoba untuk menulis utilitas rev di semua 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

Tapi saya menggunakan tr dan sed, saya ingin tahu bagaimana melakukan split dengan benar dan kemudian saya akan memperbaikinya menjadi semua bash. Hanya untuk bersenang-senang.

Gregg Leventhal
sumber
Harus ada duplikat lintas-situs di Stack Overflow, mengingat ukurannya. Salah satu kandidat adalah Bash: Split string menjadi array karakter .
Peter Mortensen
[[ $string =~ ${string//?/(.)} ]]akan ditetapkan BASH_REMATCH[]sesuai kebutuhan, lihat jawaban saya untuk pertanyaan yang ditanyakan oleh Peter Mortensen untuk penjelasan.
mr.spuratic

Jawaban:

12
s="hello"
declare -a a   # define array a
for ((i=0; i<${#s}; i++)); do a[$i]="${s:$i:1}"; done
declare -p a   # print array a in a reusable form

Keluaran:

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

atau (harap dicatat komentarnya)

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

Keluaran:

mendeklarasikan -aa = '([0] = "h" [1] = "e" [2] = "l" [3] = "l" [4] = "o")'
Cyrus
sumber
1
Yang kedua bagus tetapi hanya berfungsi (dalam hal ini) karena Anda tidak mengutip "$ c", sehingga akan menurunkan spasi dan memperluas bintang dalam $ s.
rici
2
Pilihan kedua harus: while read -N 1 c; do a+=("$c"); done <<< "$s". The -Nmemungkinkan untuk membaca bahkan baris, dan kutipan ("$c")menghindari ekspansi pathname (dan beberapa masalah lain).
1
Tentu saja, jika baris terakhir harus dikoreksi, mengubah baris yang diberikan kepada: while read -N 1 c; do a+=("$c"); done <<< "$s"xdan kemudian menghapus baris terakhir dan x menambahkan: unset a[${#a[@]}-1]; unset a[${#a[@]}-1].
4

Untuk membagi string menjadi array karakter, dengan pembatas nol, Anda dapat:

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

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

Dengan pembatas selain null, Anda dapat:

set -f
str='1,2,3,4,5'
IFS=',' arr=($str)
printf '%s\n' "${arr[@]}"
cuonglm
sumber
Jika IFSdapat diatur, maka Anda hanya dapat melakukan: IFS=',' arr=($str).
muru
2
@uru: Anda akan terjebak dengan gumpalan dalam kasus itu. Diperbarui dengan menonaktifkan glob.
cuonglm
@ Binzebra: Ah, ya, kutipan saya yang salah dan hilang. Memperbaikinya, terima kasih.
cuonglm
2

Hanya untuk bersenang-senang (dan kerang lainnya) varian lainnya:

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

Dan cek

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

akan dicetak

letter [0] = h
letter [1] = e
letter [2] = l
letter [3] = l
letter [4] = o
Costas
sumber
0

Metode 1:

Oneliner:

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

Kode yang diperluas:

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.

Metode 2:

Oneliner:

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

Kode yang diperluas:

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.

Terima kasih kepada @cuonglm dengan sarannya.
Secara efektif, Anda dapat menggunakan $REPLYitu adalah variabel default tempat readmembaca input.

Helio
sumber
1
Anda bisa menggunakan $REPLYsebagai ganti charvariabel.
cuonglm