배쉬 스크립트 : 각 문자의 단어 분리


17

각 글자를 별도의 줄로 나누는 방법은 무엇입니까?

예를 들어 "StackOver" 보고 싶은 경우

S
t
a
c
k
O
v
e
r

나는 bash를 처음 사용하기 때문에 어디에서 시작할지 전혀 모른다.

답변:


29

나는 사용할 것이다 grep:

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

또는 sed:

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

그리고 끝에 빈 공간이 문제가된다면 :

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

이 모든 것은 GNU / Linux를 가정합니다.


grep -o. <<< ¿ ¿ ¿ .. -o 제공된 패턴을 검색합니까? 그리고 당신의 명령에서 여기서 무엇을합니까?
Sijaan Hallak

1
@jimmij <<<가 실제로하는 일에 대한 도움을 찾을 수 없습니다! 어떤 도움?
Sijaan Hallak

3
@SijaanHallak 이것은 입력이 적은 그로스 Here string모도에 해당 echo foo | ...합니다. tldp.org/LDP/abs/html/x17837.html
jimmij

1
@SijaanHallak .\B(단어 경계와 일치하지 않음)으로 변경 되었습니다 .
jimmij

1
@SijaanHallak-다음 sed과 같이 두 번째를 떨어 뜨릴 수 있습니다 .sed -et -e's/./\n&/g;//D'
mikeserv

19

텍스트를 세로로 인쇄하려는 경우 문자 대신 그래 핀 클러스터를 분리 할 수 ​​있습니다. 예를 들어 e급성 악센트가있는 a를 사용하는 경우 :

  • 그래 핀 클러스터를 ( e의 급성 악센트 것 하나 개 그래 핀 클러스터) :

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

    (또는 grep -Po '\X'PCRE 지원으로 빌드 된 GNU grep 사용)

  • 문자 사용 (여기서는 GNU 사용 grep) :

    $ printf '%s\n' $'Ste\u301phane' | grep -o .
    S
    t
    e
    
    p
    h
    a
    n
    e
    
  • fold은 문자를 구분하기위한 것이지만 GNU fold는 멀티 바이트 문자를 지원하지 않으므로 대신 바이트를 구분합니다.

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

StackOver ASCII 문자로 구성 (문자 당 한 바이트, 그래 핀 클러스터 당 하나 개의 문자 때문에), 세 가지 모두 같은 결과를 줄 것이다.


나는 grep -Po사람이 기대하는 것을하지 않는 것에 놀랐습니다 grep -P.
jimmij

@jimmij, 무슨 뜻이야? grep -Po .문자를 찾고 (개행 문자 다음에 결합하는 급성 악센트가 유효하지 않음), grep -Po '\X'나를 위해 graphem 클러스터를 찾습니다. 제대로 작동하려면 최신 버전의 grep 및 / 또는 PCRE가 필요할 수 있습니다 (또는 시도해보십시오 grep -Po '(*UTF8)\X')
Stéphane Chazelas


6

상자에 perl6이 있는 경우 :

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

로케일에 관계없이 작업하십시오.


6

많은 awk버전으로

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

큰! 그러나 내 버전의 nAWK ( "One True AWK")에서는 작동하지 않습니다. 그러나이 트릭을 수행합니다 awk -v FS='' -v OFS='\n' '{$1=$1};1' (이후 그 휴대 성인지 궁금 -F ''ERE를 얻을 수 있습니다 //)
eruve

4

아래는 일반적인 것입니다 :

$ 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

이것은 끝에 새로운 줄을 인쇄 할 때 도움이되지 않습니다
Sijaan Hallak

4

bash에서 답변을 구체적으로 요청했기 때문에 다음을 순수 bash에서 수행하는 방법이 있습니다.

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

이것은 " here document " 의 끝에 줄 바꿈 문자를 붙 입니다. 이를 피하고 bash 루프를 사용하여 문자를 계속 반복 printf하려면 줄 바꿈을 피하십시오.

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

4

또한 명령 행에서 Python 2를 사용할 수 있습니다.

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

또는:

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

또는 Python 3의 경우 ( 1_CR에서 언급 한 바와 같이) :

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

4

fold (1)명령을 사용할 수 있습니다 . grepand 보다 더 효율적 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
$

한 가지 중요한 차이점은 fold가 출력에서 ​​빈 줄을 재현한다는 것입니다.

$ 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

다음과 같은 멀티 바이트 문자를 처리 할 수 ​​있습니다.

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

버퍼링이없고 문자가 전체 가 되 자마자 인쇄되기 때문에 라이브 입력으로 작업 할 때 매우 편리합니다 .


NP, 로케일에 대한 메모를 추가해야합니까?
cuonglm

Stéphane Chazelas 답변과 같은 문자를 결합하는 데는 효과가 없지만 적절한 정규화를 사용하면 이것이 중요하지 않습니다.
kay는 SE

@Kay- 원하는 경우 문자를 결합하는 데 효과적 sed입니다. 이것이 바로 스크립트입니다. 나는 지금 당장 글을 쓰지 않을 것입니다. 그러나 터미널을 읽을 때 정말 유용합니다.
mikeserv

@cuonglm-원한다면. 그러나 괜찮은 libc가 주어지면 로케일에서 작동해야합니다.
mikeserv

참고 dd나오지도의 동작은 POSIX에 따라 지정 될 수 있도록 출력이 더 이상 텍스트를하지 않도록, 멀티 바이트 문자를 중단합니다.
Stéphane Chazelas

3

단어 경계도 사용할 수 있습니다 ..

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

1

bash에서 :

이것은 모든 텍스트에서 작동하며 bash 내부 (외부 유틸리티는 호출되지 않음)에서만 작동하므로 매우 짧은 문자열에서는 빠릅니다.

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

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

산출:

S
t
é
p
h
a
n
e

á
à
é
è
ë
ê
ế
e

IFS를 변경하고 위치 매개 변수를 변경해도 괜찮다면 서브 쉘 호출을 피할 수도 있습니다.

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

여기에 업데이트 는 해키 | 빠른 | 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

더 굉장히

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
}

이것에 다른 결과를 줄 수 fold -b1있습니까?
JigglyNaga

각 바이트의 너비가 1이므로 결과는 동일합니다!
Jonah

1
그러면 어떻게 이전 답변 과 중복되지 않습니까?
JigglyNaga

그것은 다른 argyment와 동일한 cmd를 보여주기 때문에, 그것은 반갑습니다.
요나

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

이렇게하면 단어가 분리되어 배열에 저장됩니다 var.


1
for x in $(echo "$yourWordhere" | grep -o '.')
do
    code to perform operation on individual character $x of your word
done
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.