Script de bash: palavra dividida em cada letra

14

Como posso dividir as letras de uma palavra, com cada letra em uma linha separada?

Por exemplo, dado "StackOver" Eu gostaria de ver

S
t
a
c
k
O
v
e
r

Sou novo no bash, por isso não tenho ideia de por onde começar.

    
por Sijaan Hallak 05.01.2016 / 00:41

15 respostas

27

Eu usaria grep :

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

ou sed :

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

E se o espaço vazio no final for um problema:

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

Tudo isso assumindo o GNU / Linux.

    
por 05.01.2016 / 00:49
18

Você pode querer quebrar em clusters de grafema em vez de caracteres se a intenção for imprimir texto verticalmente. Por exemplo, com um e com um sotaque agudo:

  • Com clusters de grafema ( e com seu sotaque agudo seria um cluster de grafema):

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

    (ou grep -Po '\X' com o GNU grep construído com suporte a PCRE)

  • Com caracteres (aqui com GNU grep ):

    $ printf '%s\n' $'Ste\u301phane' | grep -o .
    S
    t
    e
    
    p
    h
    a
    n
    e
    
  • fold foi criado para quebrar caracteres, mas o GNU fold não suporta caracteres de múltiplos bytes, por isso quebra em bytes:

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

Em StackOver que consiste apenas em caracteres ASCII (portanto, um byte por caractere, um caractere por cluster grapheme), todos os três forneceriam o mesmo resultado.

    
por 05.01.2016 / 01:07
6

Se você tiver perl6 em sua caixa:

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

funcione independentemente da sua localidade.

    
por 05.01.2016 / 02:42
5

Com muitas awk versões

awk -F '' -v OFS='\n' '{$1=$1};1' <<<'StackOver'
    
por 05.01.2016 / 05:16
4

O abaixo será genérico:

$ awk -F '' \
   'BEGIN { RS = ""; OFS = "\n"} {for (i=1;i<=NF;i++) $i = $i; print }' <file_name>
    
por 05.01.2016 / 07:56
4
echo StackOver | sed -e 's/./&\n/g'
S
t
a
c
k
O
v
e
r
    
por 05.01.2016 / 05:11
4

Como você especificamente pediu uma resposta no bash, aqui está uma maneira de fazer isso no bash:

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

Observe que isso pegará a nova linha no final do " documento aqui ". Se você quiser evitar isso, mas ainda repetir os caracteres com um loop bash, use printf para evitar a nova linha.

printf StackOver | while read -rn1; do echo "$REPLY" ; done
    
por 05.01.2016 / 23:16
4

Além disso, o Python 2 pode ser usado a partir da linha de comando:

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

ou:

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

ou (como comentado por 1_CR) com Python 3 :

python3 -c "print(*'StackOver',sep='\n')"
    
por 05.01.2016 / 12:57
4

Você pode usar o comando fold (1) . É mais eficiente que grep e 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
$

Uma diferença significativa é que o fold reproduz linhas vazias na saída:

$ 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
$ 
    
por 06.01.2016 / 06:45
3

Você pode manipular caracteres multibyte como:

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

O que pode ser muito útil quando você está trabalhando com a entrada ao vivo porque não há buffering e um caractere é impresso assim que é todo .

    
por 05.01.2016 / 02:12
3

Você também pode usar limites de palavras.

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

No bash:

Isso funciona com qualquer texto e com apenas internals bash (nenhum utilitário externo chamado), portanto, deve ser rápido em strings muito curtas.

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

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

Saída:

S
t
é
p
h
a
n
e

á
à
é
è
ë
ê
ế
e

Se não houver problema em alterar o IFS e alterar os parâmetros posicionais, você também poderá evitar a chamada do sub-shell:

str="Stéphane áàéèëêếe"
[[ $str =~ ${str//?/(.)} ]]
set -- "${BASH_REMATCH[@]:1}"
IFS=$'\n'
echo "$*"
    
por 23.11.2016 / 22:37
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

atualizações aqui está a maneira hacky | mais rápida | pureBashBased!

$ 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

para mais 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
}
    
por 25.07.2016 / 14:01
1
read -a var <<< $(echo "$yourWordhere" | grep -o "." | tr '\n' ' ')

isso dividirá sua palavra e armazenará no array var .

    
por 31.08.2018 / 05:43
0

for x in $(echo "$yourWordhere" | grep -o '.')
do
código para executar operação em caracteres individuais $ x da sua palavra
done

    
por 12.09.2018 / 09:28