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.

Sijaan Hallak
quelle

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.

jimmij
quelle
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.

Stéphane Chazelas
quelle
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
2
@SijaanHallak Diese könnten hilfreich sein: joelonsoftware.com/articles/Unicode.html , eev.ee/blog/2015/09/12/dark-corners-of-unicode
jpmc26
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.

cuonglm
quelle
6

Mit vielen awkVersionen

awk -F '' -v OFS='\n' '{$1=$1};1' <<<'StackOver'
iruvar
quelle
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>
user150073
quelle
4
echo StackOver | sed -e 's/./&\n/g'
S
t
a
c
k
O
v
e
r
Henderson
quelle
Dies wird nicht helfen, da am Ende eine neue Zeile
gedruckt wird
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
Wyrm
quelle
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')"
ein Gold
quelle
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
$ 
joeytwiddle
quelle
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 .

mikeserv
quelle
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
Avinash Raj
quelle
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 "$*"
Sorontar
quelle
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
}
Jona
quelle
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.

Chinmay Katil
quelle
1
for x in $(echo "$yourWordhere" | grep -o '.')
do
    code to perform operation on individual character $x of your word
done
Chinmay Katil
quelle