Bash-Skript: Wort auf jeden Buchstaben aufteilen


17

Wie kann ich die Buchstaben eines Wortes so aufteilen, dass jeder Buchstabe in einer eigenen Zeile steht?

Zum Beispiel "StackOver" würde ich gerne sehen

S
t
a
c
k
O
v
e
r

Ich bin neu im Bashing, also habe ich keine Ahnung, wo ich anfangen soll.

Antworten:


29

Ich würde verwenden grep:

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

oder sed:

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

Und wenn der leere Raum am Ende ein Problem ist:

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

Das alles unter der Voraussetzung von GNU / Linux.


grep -o. <<< ¿¿¿.. -o sucht nach dem angegebenen MUSTER oder? und was macht es hier in deinem Befehl?
Sijaan Hallak

1
@jimmij Ich kann keine Hilfe finden, was <<< wirklich tut! irgendeine Hilfe?
Sijaan Hallak

3
@SijaanHallak Dies ist ein so genanntes Brutto- Here stringModo-Äquivalent von echo foo | ...nur weniger Tippen. Siehe tldp.org/LDP/abs/html/x17837.html
jimmij

1
@SijaanHallak ändern .auf \B(stimmt nicht mit der Wortgrenze überein).
Jimmy

1
@SijaanHallak - Sie können die Sekunde sedwie fallen lassen:sed -et -e's/./\n&/g;//D'
mikeserv

19

Möglicherweise möchten Sie anstelle von Zeichen in Graphem-Clustern unterbrechen, wenn der Text vertikal gedruckt werden soll. Zum Beispiel mit einem emit einem akuten Akzent:

  • Mit Graphemclustern ( emit seinem akuten Akzent wäre dies ein Graphemcluster):

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

    (oder grep -Po '\X'mit GNU grep, das mit PCRE-Unterstützung erstellt wurde)

  • Mit Zeichen (hier mit GNU grep):

    $ printf '%s\n' $'Ste\u301phane' | grep -o .
    S
    t
    e
    
    p
    h
    a
    n
    e
    
  • foldsoll Zeichen unterbrechen, aber GNU foldunterstützt keine Mehrbyte-Zeichen, so dass es stattdessen auf Bytes unterbricht:

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

Bei StackOver, das nur aus ASCII-Zeichen besteht (also ein Byte pro Zeichen, ein Zeichen pro Graphemcluster), führen alle drei zu demselben Ergebnis.


Ich bin überrascht, grep -Podass ich nicht das tue, was man erwarten würde (wie es der grep -PFall ist).
Jimmy

@jimmij, was meinst du? grep -Po .Findet Zeichen (und ein kombinierter Akzent nach einem Newline-Zeichen ist ungültig) und grep -Po '\X'findet Graphem-Cluster für mich. Möglicherweise benötigen Sie eine aktuelle Version von grep und / oder PCRE, um ordnungsgemäß zu funktionieren (oder es zu versuchen grep -Po '(*UTF8)\X')
Stéphane Chazelas


6

Wenn Sie perl6 in Ihrer Box haben:

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

arbeiten unabhängig von Ihrem Gebietsschema.


6

Mit vielen awkVersionen

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

Groß! Aber auf meiner Version von nAWK ("One True AWK") funktioniert das nicht. Doch dies funktioniert der Trick: awk -v FS='' -v OFS='\n' '{$1=$1};1' (fragen , ob das mehr tragbar ist , da -F ''die ERE ergeben könnte: //)
eruve

4

Das Folgende wird allgemeiner Natur sein:

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


4

Da Sie in bash ausdrücklich um eine Antwort gebeten haben, haben Sie hier eine Möglichkeit, dies in reiner bash zu tun:

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

Beachten Sie, dass dies die neue Zeile am Ende des " Hier-Dokuments " einfängt . Wenn Sie dies vermeiden möchten, die Zeichen jedoch weiterhin mit einer Bash-Schleife printfdurchlaufen , verwenden Sie , um die Zeilenumbrüche zu vermeiden.

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

4

Auch Python 2 kann über die Befehlszeile verwendet werden:

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

oder:

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

oder (wie von 1_CR kommentiert) mit Python 3 :

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

4

Sie können den fold (1)Befehl verwenden. Es ist effizienter als grepund 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
$

Ein wesentlicher Unterschied besteht darin, dass beim Falten leere Zeilen in der Ausgabe wiedergegeben werden:

$ 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

Sie können Multibyte-Zeichen wie folgt verarbeiten:

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

Dies kann sehr praktisch sein, wenn Sie mit Live- Eingaben arbeiten, da dort keine Pufferung erfolgt und ein Zeichen gedruckt wird, sobald es vollständig ist .


NP, sollten wir einen Hinweis zum Gebietsschema hinzufügen?
5.

Funktioniert nicht zum Kombinieren von Charakteren wie Stéphane Chazelas Antwort, aber bei richtiger Normalisierung sollte dies keine Rolle spielen.
Kay

@ Kay - es funktioniert zum Kombinieren von Zeichen, wenn Sie es möchten - dafür sedsind Skripte gedacht . Ich werde im Moment wahrscheinlich nicht darüber schreiben - ich bin ziemlich müde. Es ist jedoch sehr nützlich, wenn Sie ein Terminal lesen.
mikeserv

@ Cuonglm - wenn du magst. es sollte jedoch nur für das Gebietsschema funktionieren, vorausgesetzt, es ist eine vernünftige libc.
mikeserv

Beachten Sie, dass ddMultibyte-Zeichen unterbrochen werden, sodass die Ausgabe kein Text mehr ist und das Verhalten von sed gemäß POSIX nicht spezifiziert wird.
Stéphane Chazelas

3

Sie können auch Wortgrenzen verwenden.

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

1

In der Bash:

Dies funktioniert mit jedem Text und nur mit Bash-Interna (kein externes Hilfsprogramm). Daher sollte es bei sehr kurzen Zeichenfolgen schnell sein.

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

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

Ausgabe:

S
t
é
p
h
a
n
e

á
à
é
è
ë
ê
ế
e

Wenn es in Ordnung ist, IFS zu ändern und die Positionsparameter zu ändern, können Sie auch den Sub-Shell-Aufruf vermeiden:

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

Updates gibt es hier auf die abgefahrenste | schnellste | pureBashBased-Art!

$ 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

für mehr awesomeness

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
}

Wird dies jemals zu unterschiedlichen Ergebnissen führen fold -b1?
JigglyNaga

da jedes Byte eine Breite = 1 hat, ist das Ergebnis dasselbe!
Jonah

1
Wie kommt es also, dass dies kein Duplikat der früheren Antwort ist ?
JigglyNaga

denn es zeigt das gleiche cmd mit verschiedenen argyment, und das ist gut zu wissen.
Jonah

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

Dadurch wird Ihr Wort aufgeteilt und in einem Array gespeichert var.


1
for x in $(echo "$yourWordhere" | grep -o '.')
do
    code to perform operation on individual character $x of your word
done
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.