Bash脚本:在每个字母上拆分单词


Answers:


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搜索提供的PATTERN对吗?以及您的命令在这里做什么?
Sijaan Hallak'1

1
@jimmij我对<<<确实没有任何帮助!有什么帮助吗?
Sijaan Hallak

3
@SijaanHallak所谓的Here string,grosso modo等效于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重音符号的:

  • 对于字素簇(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
    

仅由ASCII字符组成的StackOver上(因此,每个字符一个字节,每个字素簇一个字符),所有这三个将给出相同的结果。


我很惊讶grep -Po没有像人们期望的那样grep -P做。
jimmij

@jimmij,你是什么意思?grep -Po .查找字符(并且在换行符后合并尖音符号无效),并grep -Po '\X'为我查找字素簇。您可能需要一个最近grep和/或PCRE的版本才能正常工作(或尝试grep -Po '(*UTF8)\X'
斯特凡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版本(“一个真实的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

由于您专门要求使用bash回答,因此以下是使用纯bash进行回答的方法:

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

请注意,这将在“ 此处文档 ” 末尾捕获换行符。如果要避免这种情况,但仍然使用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

或者(如1_CR所述)与Python 3

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

4

您可以使用该fold (1)命令。它比grep和更有效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
$

一个重要的区别是,折叠将在输出中重现空行:

$ 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 '16

不适用于结合StéphaneChazelas答案之类的字符,但是通过适当的规范化,这无关紧要。

@Kay-如果需要,它可用于组合字符-这就是sed脚本的用途。我现在不太可能写一个-我很困。但是,在阅读终端时它确实很有用。
mikeserv

@cuonglm-如果您愿意。不过,在合理的libc条件下,它应该只适用于语言环境。
mikeserv

请注意,这dd将破坏多字节字符,因此输出将不再是文本,因此根据POSIX,未指定sed的行为。
斯特凡Chazelas


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和更改位置参数,也可以避免子shell调用:

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

这里更新是hacky | fastest | 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

由于每个字节的width = 1,结果将相同!
乔纳

1
那么,这与先前的答案又有何不同?
JigglyNaga

因为它显示相同的cmd和不同的argyment,很高兴知道。
乔纳

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

这将拆分您的单词并将其存储在array中var


1
for x in $(echo "$yourWordhere" | grep -o '.')
do
    code to perform operation on individual character $x of your word
done
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.