Bash betiği: her harfe bölünen kelime


17

Bir kelimenin harflerini, her harf ayrı bir satırda olacak şekilde nasıl bölebilirim?

Örneğin, "StackOver" görmek istediğim gibi

S
t
a
c
k
O
v
e
r

Bash için yeniyim, bu yüzden nereden başlayacağımla ilgili hiçbir fikrim yok.

Yanıtlar:


29

Kullanacağım grep:

$ grep -o . <<<"StackOver"
S
t
a
c
k
O
v
e
r

veya sed:

$ sed 's/./&\n/g' <<<"StackOver"
S
t
a
c
k
O
v
e
r

Ve sonunda boş alan bir sorunsa:

sed 's/\B/&\n/g' <<<"StackOver"

Bunların hepsi GNU / Linux olduğunu varsayar.


grep -o. <<< ¿¿¿.. -o sağlanan DESEN'i arar değil mi? ve burada emrinizde ne yapar?
Sijaan Hallak

1
@jimmij <<< gerçekten ne yaptığı hakkında herhangi bir yardım bulamıyorum! herhangi bir yardım?
Sijaan Hallak

3
@SijaanHallak Bu, daha az yazmanın Here stringgrosso modo eşdeğeri olarak adlandırılır echo foo | .... Bkz tldp.org/LDP/abs/html/x17837.html
jimmij

1
@SijaanHallak değişim .için \B(sözcük sınırında uymuyor).
jimmij

1
@SijaanHallak - ikinci sedgibi bırakabilirsiniz :sed -et -e's/./\n&/g;//D'
mikeserv

19

Amaç metni dikey olarak yazdırmaksa, karakterler yerine grafik kümelerini kırmak isteyebilirsiniz. Örneğin e, akut aksanlı bir a:

  • Grafeme kümeleriyle ( eakut vurgusu ile bir grafik kümesi kümesi olur):

    $ perl -CLAS -le 'for (@ARGV) {print for /\X/g}' $'Ste\u301phane'
    S
    t
    é
    p
    h
    a
    n
    e
    

    (veya grep -Po '\X'PCRE desteği ile oluşturulmuş GNU grep ile)

  • Karakterlerle (burada GNU ile grep):

    $ printf '%s\n' $'Ste\u301phane' | grep -o .
    S
    t
    e
    
    p
    h
    a
    n
    e
    
  • foldkarakterleri kırmaya yöneliktir, ancak GNU foldçok baytlı karakterleri desteklemez, bunun yerine baytlara ayrılır:

    $ printf '%s\n' $'Ste\u301phane' | fold -w 1
    S
    t
    e
    �
    �
    p
    h
    a
    n
    e
    

Yalnızca ASCII karakterlerden (yani karakter başına bir bayt, grafik kümesi başına bir karakter) oluşan StackOver üzerinde , üçü de aynı sonucu verir.


Şaşırdım grep -Pobiri beklendiği gibi grep -Pyapmaz (olduğu gibi ).
jimmij

@jimmij, ne demek istiyorsun? grep -Po .karakterleri bulur (ve yeni satır karakterini izleyen akut aksanı birleştirir) ve grep -Po '\X'benim için grafik kümeleri bulur. Düzgün çalışması (veya denemesi grep -Po '(*UTF8)\X') için grep ve / veya PCRE'nin son sürümüne ihtiyacınız olabilir
Stéphane Chazelas


6

Kutunuzda perl6 varsa :

$ perl6 -e 'for @*ARGS -> $w { .say for $w.comb }' 'cường'       
c
ư
ờ
n
g

bulunduğunuz yerden bağımsız olarak çalışın.


6

Birçok awksürümü ile

awk -F '' -v OFS='\n' '{$1=$1};1' <<<'StackOver'

Harika! Ama nAWK ("One True AWK") versiyonumda bu işe yaramıyor. Ancak bu hile yapar: awk -v FS='' -v OFS='\n' '{$1=$1};1' (beri daha taşınabilir olmadığını merak -F ''ERE verim olabilir: //)
eruve

4

Aşağıdakiler genel olacaktır:

$ awk -F '' \
   'BEGIN { RS = ""; OFS = "\n"} {for (i=1;i<=NF;i++) $i = $i; print }' <file_name>

4
echo StackOver | sed -e 's/./&\n/g'
S
t
a
c
k
O
v
e
r

Sonunda yeni bir çizgi yazdırdığı için bu yardımcı olmaz
Sijaan Hallak

4

Özellikle bash'de bir cevap sorduğunuz için, bunu saf bash'da yapmanın bir yolu:

while read -rn1; do echo "$REPLY" ; done <<< "StackOver"

Bunun, " burada belge " nin sonundaki yeni satırı yakalayacağını unutmayın . Bundan kaçınmak, ancak yine de bash döngüsüne sahip karakterler üzerinde yineleme yapmak istiyorsanız printf, yeni satırdan kaçınmak için kullanın .

printf StackOver | while read -rn1; do echo "$REPLY" ; done

4

Ayrıca Python 2 komut satırından kullanılabilir:

python <<< "for x in 'StackOver':
   print x"

veya:

echo "for x in 'StackOver':
    print x" | python

veya (1_CR tarafından yorumlandığı gibi) Python 3 ile :

python3 -c "print(*'StackOver',sep='\n')"

4

fold (1)Komutu kullanabilirsiniz . Bu daha etkilidir grepve 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
$

Önemli bir fark, katlamanın çıktıda boş satırlar üretmesidir:

$ 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
$ 

3

Çok baytlı karakterleri işleyebilirsiniz:

<input \
dd cbs=1 obs=2 conv=unblock |
sed -e:c -e '/^.*$/!N;s/\n//;tc'

Canlı girişle çalışırken oldukça kullanışlı olabilir, çünkü burada arabellek yoktur ve bir karakter bütün olduğu anda yazdırılır .


NP, yerel ayar hakkında bir not eklemeli miyiz?
cuonglm

Stéphane Chazelas gibi karakterleri birleştirmek için işe yaramaz, ancak uygun normalleştirme ile bu önemli olmamalıdır.
kay - SE kötü

@Kay - karakterleri birleştirmek için 's eserleri eğer istediğiniz şey bu yıllardan - bu kadar sedkomut içindir. şu an hakkında bir şey yazmam mümkün değil - oldukça uykulu im. yine de, bir terminali okurken çok kullanışlıdır.
mikeserv

@cuonglm - isterseniz. olsa da, sadece aklı başında bir libc verilen yerel için çalışmalıdır.
mikeserv

Not ddsed davranışı POSIX göre belirtilmemiş olacak böylece çıkış artık metin olmayacak şekilde, baytlı karakterleri kıracak.
Stéphane Chazelas

3

Kelime sınırlarını da kullanabilirsiniz ..

$ perl -pe 's/(?<=.)(\B|\b)(?=.)/\n/g' <<< "StackOver"
S
t
a
c
k
O
v
e
r

1

Bash'da:

Bu, herhangi bir metinle ve yalnızca bash dahili ile (harici bir yardımcı program çağrılmaz) çalışır, bu nedenle çok kısa dizelerde hızlı olmalıdır.

str="Stéphane áàéèëêếe"

[[ $str =~ ${str//?/(.)} ]]
(set -- "${BASH_REMATCH[@]:1}"; IFS=$'\n'; echo "$*")

Çıktı:

S
t
é
p
h
a
n
e

á
à
é
è
ë
ê
ế
e

IFS'yi değiştirmek ve konum parametrelerini değiştirmek uygunsa, alt kabuk çağrısından da kaçınabilirsiniz:

str="Stéphane áàéèëêếe"
[[ $str =~ ${str//?/(.)} ]]
set -- "${BASH_REMATCH[@]:1}"
IFS=$'\n'
echo "$*"

1
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

güncellemeler burada hacky | en hızlı | pureBashBased yolu!

$ 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

daha fazla şaşkınlık için

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
}

Bu hiç farklı sonuçlar verecek fold -b1mi?
JigglyNaga

her baytın genişliği = 1 olduğundan sonuç aynı olacaktır!
Jonah

1
Peki bu önceki cevabın kopyası değil mi?
JigglyNaga

çünkü bu farklı cmd ile aynı cmd gösterir ve bunu bilmek güzel.
Jonah

1
read -a var <<< $(echo "$yourWordhere" | grep -o "." | tr '\n' ' ')

bu, kelimenizi böler ve dizide saklar var.


1
for x in $(echo "$yourWordhere" | grep -o '.')
do
    code to perform operation on individual character $x of your word
done
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.