Dalam bash saja, tidak ada perintah eksternal:
str="foobarbazblargblurg"
[[ $str =~ ${str//?/(.)} ]]
printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"
atau sebagai versi pipa satu baris:
echo foobarbazblargblurg |
{ IFS= read -r str; [[ $str =~ ${str//?/(.)} ]]; \
printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"; }
Cara kerjanya adalah mengonversi setiap karakter string menjadi "(.)" Untuk pencocokan dan tangkapan regex =~, kemudian hanya mengeluarkan ekspresi yang diambil dari BASH_REMATCH[]array, dikelompokkan sesuai kebutuhan. Ruang depan / belakang / tengah dipertahankan, hapus tanda kutip "${BASH_REMATCH[@]:1}"untuk menghilangkannya.
Di sini dibungkus dalam suatu fungsi, yang ini akan memproses argumennya atau membaca stdin jika tidak ada argumen:
function fmt4() {
while IFS= read -r str; do
[[ $str =~ ${str//?/(.)} ]]
printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"
done < <( (( $# )) && printf '%s\n' "$@" || printf '%s\n' $(< /dev/stdin) )
}
$ echo foobarbazblargblurg | fmt4
foob arba zbla rgbl urg
Anda dapat dengan mudah mengukur parameter hitungan untuk menyesuaikan string format yang sesuai.
Sebuah ruang tambahan ditambahkan, gunakan dua printfs bukan satu jika itu masalah:
printf "%s%s%s%s" "${BASH_REMATCH[@]:1:4}"
(( ${#BASH_REMATCH[@]} > 5 )) && printf " %s%s%s%s" "${BASH_REMATCH[@]:5}"
Yang pertama printfmencetak (hingga) 4 karakter pertama, yang kedua secara kondisional mencetak yang lainnya (jika ada) dengan ruang utama untuk memisahkan grup. Tes ini untuk 5 elemen bukan 4 untuk memperhitungkan elemen nol.
Catatan:
- shell
printf's %cdapat digunakan sebagai pengganti %s, %c(mungkin) membuat maksud lebih jelas, tapi itu bukan multi-byte karakter aman. Jika versi bash Anda mampu, di atas semua karakter multi-byte aman.
- shell
printfmenggunakan kembali format string-nya hingga kehabisan argumen, jadi ia hanya melahap 4 argumen sekaligus, dan menangani argumen trailing (jadi tidak perlu case tepi, tidak seperti beberapa jawaban lain di sini yang bisa dibilang salah)
BASH_REMATCH[0] adalah seluruh string yang cocok, jadi hanya output yang dimulai dari indeks 1
- gunakan
printf -v myvar ...sebagai gantinya untuk menyimpan ke variabel myvar(tunduk pada perilaku read-loop / subshell yang biasa)
- tambahkan
printf "\n"jika diperlukan
Anda dapat membuat cara di atas berfungsi zshjika Anda menggunakan array match[]sebagai ganti BASH_REMATCH[], dan kurangi 1 dari semua indeks karena zshtidak mempertahankan elemen 0 dengan seluruh kecocokan.
sedaku mencoba dulu aku bisa menendang diriku sendiri.