Как я могу разделить буквы слова с каждой буквой в отдельной строке?
Например, учитывая, что "StackOver"
я хотел бы видеть
S
t
a
c
k
O
v
e
r
Я новичок в bash, поэтому понятия не имею, с чего начать.
Как я могу разделить буквы слова с каждой буквой в отдельной строке?
Например, учитывая, что "StackOver"
я хотел бы видеть
S
t
a
c
k
O
v
e
r
Я новичок в bash, поэтому понятия не имею, с чего начать.
Ответы:
Я бы использовал 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.
Here string
гроссо-модо, эквивалентный echo foo | ...
просто меньшему количеству печатания. См. Tldp.org/LDP/abs/html/x17837.html
.
на \B
(не соответствует границе слова).
sed
как:sed -et -e's/./\n&/g;//D'
Вы можете разбивать кластеры графем вместо символов, если вы хотите печатать текст вертикально. Например, e
с острым акцентом:
С кластерами графем ( e
с его острым акцентом будет один кластер графем):
$ perl -CLAS -le 'for (@ARGV) {print for /\X/g}' $'Ste\u301phane'
S
t
é
p
h
a
n
e
(или grep -Po '\X'
с GNU grep, созданным с поддержкой PCRE)
С символами (здесь с 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
делает).
grep -Po .
находит символы (и комбинированный острый акцент после символа новой строки недопустим) и grep -Po '\X'
находит кластеры графема для меня. Вам может понадобиться последняя версия grep и / или PCRE, чтобы она работала должным образом (или попробуйте grep -Po '(*UTF8)\X'
)
Ниже будет общим:
$ awk -F '' \
'BEGIN { RS = ""; OFS = "\n"} {for (i=1;i<=NF;i++) $i = $i; print }' <file_name>
echo StackOver | sed -e 's/./&\n/g'
S
t
a
c
k
O
v
e
r
Поскольку вы специально запросили ответ в bash, вот способ сделать это в чистом bash:
while read -rn1; do echo "$REPLY" ; done <<< "StackOver"
Обратите внимание, что это поймает новую строку в конце « здесь документа ». Если вы хотите избежать этого, но по-прежнему перебираете символы с помощью цикла bash, используйте, printf
чтобы избежать перехода на новую строку.
printf StackOver | while read -rn1; do echo "$REPLY" ; done
Вы можете использовать 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
$
Одно существенное различие заключается в том, что в выводе 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
$
Вы можете обрабатывать многобайтовые символы, такие как:
<input \
dd cbs=1 obs=2 conv=unblock |
sed -e:c -e '/^.*$/!N;s/\n//;tc'
Что может быть очень удобно, когда вы работаете с живым вводом, потому что там нет буферизации и символ печатается, как только он становится целым .
sed
, для чего нужны сценарии. я вряд ли напишу об этом прямо сейчас - я довольно сонный. это действительно полезно, хотя, при чтении терминала.
dd
приведет к разрыву многобайтовых символов, поэтому выходные данные больше не будут текстовыми, поэтому поведение sed будет неопределенным в соответствии с POSIX.
Вы можете использовать границы слов также ..
$ perl -pe 's/(?<=.)(\B|\b)(?=.)/\n/g' <<< "StackOver"
S
t
a
c
k
O
v
e
r
В Баш:
Это работает с любым текстом и только с внутренними компонентами bash (внешняя утилита не вызывается), поэтому должна быть быстрой на очень коротких строках.
str="Stéphane áàéèëêếe"
[[ $str =~ ${str//?/(.)} ]]
(set -- "${BASH_REMATCH[@]:1}"; IFS=$'\n'; echo "$*")
Выход:
S
t
é
p
h
a
n
e
á
à
é
è
ë
ê
ế
e
Если можно изменить IFS и позиционные параметры, вы также можете избежать вызова sub-shell:
str="Stéphane áàéèëêếe"
[[ $str =~ ${str//?/(.)} ]]
set -- "${BASH_REMATCH[@]:1}"
IFS=$'\n'
echo "$*"
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
?
read -a var <<< $(echo "$yourWordhere" | grep -o "." | tr '\n' ' ')
это разделит ваше слово и сохранит его в массиве var
.
for x in $(echo "$yourWordhere" | grep -o '.')
do
code to perform operation on individual character $x of your word
done