Script Bash: parola divisa su ogni lettera


17

Come posso dividere le lettere di una parola, con ciascuna lettera in una riga separata?

Ad esempio, dato "StackOver" che vorrei vedere

S
t
a
c
k
O
v
e
r

Sono nuovo a bash quindi non ho idea di dove iniziare.

Risposte:


29

Vorrei usare grep:

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

oppure sed:

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

E se lo spazio vuoto alla fine è un problema:

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

Tutto questo presupponendo GNU / Linux.


grep -o. <<< ¿¿¿.. -o cerca il PATTERN fornito giusto? e cosa fa qui al tuo comando?
Sijaan Hallak,

1
@jimmij Non riesco a trovare alcun aiuto su ciò che <<< fa davvero! qualsiasi aiuto?
Sijaan Hallak,

3
@SijaanHallak Questo è il cosiddetto Here string, grosso modo equivalente di echo foo | ...appena meno battitura. Vedi tldp.org/LDP/abs/html/x17837.html
jimmij

1
@SijaanHallak cambia .in \B(non corrisponde al limite di parole).
Jimmij,

1
@SijaanHallak - puoi rilasciare il secondo sedcome:sed -et -e's/./\n&/g;//D'
mikeserv

19

È possibile che si desideri interrompere i grappoli anziché i caratteri se si intende stampare il testo in verticale. Ad esempio con una econ un accento acuto:

  • Con i grappoli ( econ il suo accento acuto sarebbe un grappolo):

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

    (o grep -Po '\X'con GNU grep costruito con supporto PCRE)

  • Con personaggi (qui con GNU grep):

    $ printf '%s\n' $'Ste\u301phane' | grep -o .
    S
    t
    e
    
    p
    h
    a
    n
    e
    
  • foldè pensato per rompere i caratteri, ma GNU foldnon supporta i caratteri multi-byte, quindi si rompe sui byte invece:

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

Su StackOver che consiste solo di caratteri ASCII (quindi un byte per carattere, un carattere per cluster grapheme), tutti e tre darebbero lo stesso risultato.


Sono sorpreso grep -Poche non faccia ciò che ci si aspetterebbe (come grep -Pfa).
Jimmij,

@jimmij, che vuoi dire? grep -Po .trova i caratteri (e un accento acuto combinato che segue un carattere di nuova riga non è valido) e grep -Po '\X'trova graphem grappoli per me. Potrebbe essere necessaria una versione recente di grep e / o PCRE per funzionare correttamente (o provare grep -Po '(*UTF8)\X')
Stéphane Chazelas,


6

Se hai perl6 nella tua scatola:

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

lavorare indipendentemente dalle impostazioni locali.


6

Con molte awkversioni

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

Grande! Ma sulla mia versione di nAWK ("One True AWK") che non funziona. Tuttavia, questo fa il trucco: awk -v FS='' -v OFS='\n' '{$1=$1};1' (chiedo se questo è più portabile in quanto -F ''potrebbe cedere l'ERE: //)
Erúvë

4

Di seguito sarà generico:

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


4

Dato che hai specificamente chiesto una risposta in bash, ecco un modo per farlo in puro bash:

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

Si noti che questo prenderà la nuova riga alla fine del " documento qui ". Se vuoi evitarlo, ma continua a scorrere i personaggi con un ciclo bash, usa printfper evitare la nuova riga.

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

4

Anche Python 2 può essere utilizzato dalla riga di comando:

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

o:

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

o (come commentato da 1_CR) con Python 3 :

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

4

Puoi usare il fold (1)comando È più efficiente di grepe 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
$

Una differenza significativa è che fold riprodurrà righe vuote nell'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
$ 

3

Puoi gestire caratteri multibyte come:

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

Il che può essere molto utile quando lavori con input live perché non c'è buffering lì e un personaggio viene stampato non appena è intero .


NP, dovremmo aggiungere una nota sulla locale?
cuonglm,

Non funziona per la combinazione di personaggi come la risposta di Stéphane Chazelas, ma con un'adeguata normalizzazione questo non dovrebbe importare.
Kay è deluso a SE il

@Kay - E 'lavori per la combinazione di caratteri, se si vuole a - E' quello che sedgli script sono per. probabilmente non ne scriverò uno proprio ora - sono piuttosto assonnato. è molto utile, tuttavia, quando si legge un terminale.
Mikeserv,

@cuonglm - se ti piace. dovrebbe funzionare solo per le impostazioni locali, data una libc sana, però.
Mikeserv,

Si noti che ddinterromperà i caratteri multibyte, quindi l'output non sarà più testo, quindi il comportamento di sed non sarà specificato secondo POSIX.
Stéphane Chazelas,

3

Puoi usare anche i confini delle parole.

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

1

In bash:

Funziona con qualsiasi testo e con solo interni bash (nessuna utility esterna chiamata), quindi dovrebbe essere veloce su stringhe molto brevi.

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

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

Produzione:

S
t
é
p
h
a
n
e

á
à
é
è
ë
ê
ế
e

Se è possibile modificare IFS e modificare i parametri posizionali, è anche possibile evitare la chiamata della shell secondaria:

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

gli aggiornamenti qui sono il modo più veloce e veloce |

$ 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

per più suggestione

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
}

Questo darà mai risultati diversi fold -b1?
JigglyNaga,

poiché ogni byte ha una larghezza = 1 il risultato sarà lo stesso!
Giona,

1
Quindi, in che modo questo non è un duplicato della risposta precedente ?
JigglyNaga,

perché mostra lo stesso cmd con argomentazioni diverse, ed è bello saperlo.
Giona,

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

questo dividerà la tua parola e la memorizzerà nella matrice var.


1
for x in $(echo "$yourWordhere" | grep -o '.')
do
    code to perform operation on individual character $x of your word
done
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.