Bagaimana saya bisa membagi huruf kata, dengan masing-masing huruf dalam baris yang terpisah?
Misalnya, mengingat "StackOver"
saya ingin melihat
S
t
a
c
k
O
v
e
r
Saya baru mengenal bash jadi saya tidak tahu harus mulai dari mana.
Bagaimana saya bisa membagi huruf kata, dengan masing-masing huruf dalam baris yang terpisah?
Misalnya, mengingat "StackOver"
saya ingin melihat
S
t
a
c
k
O
v
e
r
Saya baru mengenal bash jadi saya tidak tahu harus mulai dari mana.
Jawaban:
Saya akan menggunakan grep
:
$ grep -o . <<<"StackOver"
S
t
a
c
k
O
v
e
r
atau sed
:
$ sed 's/./&\n/g' <<<"StackOver"
S
t
a
c
k
O
v
e
r
Dan jika ruang kosong pada akhirnya adalah masalah:
sed 's/\B/&\n/g' <<<"StackOver"
Semua itu dengan asumsi GNU / Linux.
Here string
, grosso modo setara dengan echo foo | ...
kurang mengetik. Lihat tldp.org/LDP/abs/html/x17837.html
.
menjadi \B
(tidak cocok dengan batas kata).
sed
seperti:sed -et -e's/./\n&/g;//D'
Anda mungkin ingin memecah cluster grapheme daripada karakter jika tujuannya adalah untuk mencetak teks secara vertikal. Misalnya dengan e
aksen akut:
Dengan cluster grapheme ( e
dengan aksen akutnya akan menjadi satu cluster grapheme):
$ perl -CLAS -le 'for (@ARGV) {print for /\X/g}' $'Ste\u301phane'
S
t
é
p
h
a
n
e
(atau grep -Po '\X'
dengan grep GNU yang dibangun dengan dukungan PCRE)
Dengan karakter (di sini dengan GNU grep
):
$ printf '%s\n' $'Ste\u301phane' | grep -o .
S
t
e
p
h
a
n
e
fold
dimaksudkan untuk memecah karakter, tetapi GNU fold
tidak mendukung karakter multi-byte, jadi ia memecah pada byte:
$ printf '%s\n' $'Ste\u301phane' | fold -w 1
S
t
e
�
�
p
h
a
n
e
Pada StackOver yang hanya terdiri dari karakter ASCII (jadi satu byte per karakter, satu karakter per cluster grapheme), ketiganya akan memberikan hasil yang sama.
grep -Po
tidak melakukan apa yang diharapkan (seperti grep -P
halnya).
grep -Po .
menemukan karakter (dan aksen akut kombinasi setelah karakter baris baru tidak valid), dan grep -Po '\X'
menemukan cluster graphem untuk saya. Anda mungkin memerlukan versi grep dan / atau PCRE terbaru agar dapat berfungsi dengan baik (atau coba grep -Po '(*UTF8)\X'
)
Dengan banyak awk
versi
awk -F '' -v OFS='\n' '{$1=$1};1' <<<'StackOver'
awk -v FS='' -v OFS='\n' '{$1=$1};1'
(bertanya-tanya apakah itu lebih portabel karena -F ''
mungkin menghasilkan ERE: //
)
Di bawah ini akan menjadi generik:
$ awk -F '' \
'BEGIN { RS = ""; OFS = "\n"} {for (i=1;i<=NF;i++) $i = $i; print }' <file_name>
echo StackOver | sed -e 's/./&\n/g'
S
t
a
c
k
O
v
e
r
Karena Anda secara khusus meminta jawaban dalam bash, inilah cara untuk melakukannya dalam bash murni:
while read -rn1; do echo "$REPLY" ; done <<< "StackOver"
Perhatikan bahwa ini akan menangkap baris baru di akhir dokumen "di sini ". Jika Anda ingin menghindari itu, tetapi tetap mengulangi karakter dengan bash loop, gunakan printf
untuk menghindari baris baru.
printf StackOver | while read -rn1; do echo "$REPLY" ; done
Anda bisa menggunakan fold (1)
perintah. Ini lebih efisien daripada grep
dan sed
.
$ time grep -o . <bigfile >/dev/null
real 0m3.868s
user 0m3.784s
sys 0m0.056s
$ time fold -b1 <bigfile >/dev/null
real 0m0.555s
user 0m0.528s
sys 0m0.016s
$
Satu perbedaan signifikan adalah lipatan akan mereproduksi garis kosong di output:
$ grep -o . <(printf "A\nB\n\nC\n\n\nD\n")
A
B
C
D
$ fold -b1 <(printf "A\nB\n\nC\n\n\nD\n")
A
B
C
D
$
Anda dapat menangani karakter multibyte seperti:
<input \
dd cbs=1 obs=2 conv=unblock |
sed -e:c -e '/^.*$/!N;s/\n//;tc'
Yang bisa sangat berguna ketika Anda bekerja dengan input langsung karena tidak ada buffering di sana dan karakter dicetak segera setelah semuanya utuh .
sed
skrip. saya tidak akan menulis yang benar tentang sekarang - saya cukup mengantuk. itu benar-benar berguna, ketika membaca terminal.
dd
akan memecah karakter multibyte, sehingga output tidak akan menjadi teks lagi sehingga perilaku sed tidak ditentukan sesuai POSIX.
Anda dapat menggunakan batas kata juga ..
$ perl -pe 's/(?<=.)(\B|\b)(?=.)/\n/g' <<< "StackOver"
S
t
a
c
k
O
v
e
r
Dalam bash:
Ini berfungsi dengan teks apa saja dan dengan hanya bash internal (tidak ada utilitas eksternal yang disebut), jadi, harus cepat pada string yang sangat singkat.
str="Stéphane áàéèëêếe"
[[ $str =~ ${str//?/(.)} ]]
(set -- "${BASH_REMATCH[@]:1}"; IFS=$'\n'; echo "$*")
Keluaran:
S
t
é
p
h
a
n
e
á
à
é
è
ë
ê
ế
e
Jika boleh mengubah IFS dan mengubah parameter posisi, Anda juga dapat menghindari panggilan sub-shell:
str="Stéphane áàéèëêếe"
[[ $str =~ ${str//?/(.)} ]]
set -- "${BASH_REMATCH[@]:1}"
IFS=$'\n'
echo "$*"
s=stackoverflow;
$ time echo $s | fold -w1
s
t
a
c
k
o
v
e
r
real 0m0.014s
user 0m0.000s
sys 0m0.004s
pembaruan di sini adalah cara hacky | tercepat | pureBash!
$ time eval eval printf \'%s\\\\n\' \\\${s:\{0..$((${#s}-1))}:1}
s
t
a
c
k
o
v
e
r
real 0m0.001s
user 0m0.000s
sys 0m0.000s
untuk lebih kedahsyatan
function foldh ()
{
if (($#)); then
local s="$@";
eval eval printf \'%s\\\\n\' \\\"\\\${s:\{0..$((${#s}-1))}:1}\\\";
else
while read s; do
eval eval printf \'%s\\\\n\' \\\"\\\${s:\{0..$((${#s}-1))}:1}\\\";
done;
fi
}
function foldv ()
{
if (($#)); then
local s="$@";
eval eval echo \\\"\\\${s:\{0..$((${#s}-1))}:1}\\\";
else
while read s; do
eval eval echo \\\"\\\${s:\{0..$((${#s}-1))}:1}\\\";
done;
fi
}
fold -b1
?
read -a var <<< $(echo "$yourWordhere" | grep -o "." | tr '\n' ' ')
ini akan membagi kata Anda dan menyimpannya dalam array var
.
for x in $(echo "$yourWordhere" | grep -o '.')
do
code to perform operation on individual character $x of your word
done