Làm cách nào tôi có thể chia các chữ cái của một từ, với mỗi chữ cái trong một dòng riêng biệt?
Ví dụ, cho "StackOver"
tôi muốn xem
S
t
a
c
k
O
v
e
r
Tôi mới làm quen với bash nên tôi không biết bắt đầu từ đâu.
Làm cách nào tôi có thể chia các chữ cái của một từ, với mỗi chữ cái trong một dòng riêng biệt?
Ví dụ, cho "StackOver"
tôi muốn xem
S
t
a
c
k
O
v
e
r
Tôi mới làm quen với bash nên tôi không biết bắt đầu từ đâu.
Câu trả lời:
Tôi sẽ sử dụng grep
:
$ grep -o . <<<"StackOver"
S
t
a
c
k
O
v
e
r
hoặc sed
:
$ sed 's/./&\n/g' <<<"StackOver"
S
t
a
c
k
O
v
e
r
Và nếu không gian trống ở cuối là một vấn đề:
sed 's/\B/&\n/g' <<<"StackOver"
Tất cả điều đó giả sử GNU / Linux.
Here string
, grosso modo tương đương với việc echo foo | ...
chỉ cần gõ ít hơn. Xem tldp.org/LDP/abs/html/x17837.html
.
thành \B
(không khớp với ranh giới từ).
sed
như sau:sed -et -e's/./\n&/g;//D'
Bạn có thể muốn phá vỡ các cụm grapheme thay vì các ký tự nếu mục đích là in văn bản theo chiều dọc. Ví dụ với một e
dấu trọng âm:
Với các cụm grapheme ( e
với giọng cấp tính của nó sẽ là một cụm grapheme):
$ perl -CLAS -le 'for (@ARGV) {print for /\X/g}' $'Ste\u301phane'
S
t
é
p
h
a
n
e
(hoặc grep -Po '\X'
với GNU grep được xây dựng với sự hỗ trợ của PCRE)
Với các ký tự (ở đây có GNU grep
):
$ printf '%s\n' $'Ste\u301phane' | grep -o .
S
t
e
p
h
a
n
e
fold
có nghĩa là phá vỡ các ký tự, nhưng GNU fold
không hỗ trợ các ký tự nhiều byte, do đó, nó phá vỡ các byte thay vào đó:
$ printf '%s\n' $'Ste\u301phane' | fold -w 1
S
t
e
�
�
p
h
a
n
e
Trên StackOver chỉ bao gồm các ký tự ASCII (vì vậy một byte cho mỗi ký tự, một ký tự trên cụm grapheme), cả ba sẽ cho kết quả như nhau.
grep -Po
không làm những gì người ta mong đợi (như thế grep -P
).
grep -Po .
tìm các ký tự (và một dấu kết hợp cấp tính theo sau một ký tự dòng mới là không hợp lệ) và grep -Po '\X'
tìm các cụm biểu đồ cho tôi. Bạn có thể cần một phiên bản gần đây của grep và / hoặc PCRE để nó hoạt động chính xác (hoặc thử grep -Po '(*UTF8)\X'
)
Với nhiều awk
phiên bản
awk -F '' -v OFS='\n' '{$1=$1};1' <<<'StackOver'
awk -v FS='' -v OFS='\n' '{$1=$1};1'
(tự hỏi liệu điều đó có dễ mang theo hơn không vì -F ''
có thể mang lại ERE //
:)
Dưới đây sẽ là chung chung:
$ 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
Vì bạn đặc biệt yêu cầu một câu trả lời trong bash, đây là một cách để làm điều đó trong bash thuần túy:
while read -rn1; do echo "$REPLY" ; done <<< "StackOver"
Lưu ý rằng điều này sẽ bắt dòng mới ở cuối " tài liệu ở đây ". Nếu bạn muốn tránh điều đó, nhưng vẫn lặp lại các ký tự có vòng lặp bash, hãy sử dụng printf
để tránh dòng mới.
printf StackOver | while read -rn1; do echo "$REPLY" ; done
Bạn có thể sử dụng fold (1)
lệnh. Nó hiệu quả hơn grep
và 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
$
Một sự khác biệt đáng kể là nếp gấp sẽ tái tạo các dòng trống trong đầu ra:
$ 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
$
Bạn có thể xử lý các ký tự đa nhân như:
<input \
dd cbs=1 obs=2 conv=unblock |
sed -e:c -e '/^.*$/!N;s/\n//;tc'
Điều này có thể khá tiện lợi khi bạn làm việc với đầu vào trực tiếp vì không có bộ đệm ở đó và một ký tự được in ngay sau khi toàn bộ .
sed
các kịch bản dành cho. Tôi không có khả năng viết ngay bây giờ - tôi khá buồn ngủ. Tuy nhiên, nó thực sự hữu ích khi đọc một thiết bị đầu cuối.
dd
sẽ phá vỡ các ký tự đa dòng, do đó đầu ra sẽ không còn là văn bản nữa nên hành vi của sed sẽ không được chỉ định theo POSIX.
Bạn cũng có thể sử dụng ranh giới từ ..
$ perl -pe 's/(?<=.)(\B|\b)(?=.)/\n/g' <<< "StackOver"
S
t
a
c
k
O
v
e
r
Trong bash:
Điều này hoạt động với bất kỳ văn bản nào và chỉ với nội bộ bash (không có tiện ích bên ngoài được gọi), vì vậy, nên nhanh chóng trên các chuỗi rất ngắn.
str="Stéphane áàéèëêếe"
[[ $str =~ ${str//?/(.)} ]]
(set -- "${BASH_REMATCH[@]:1}"; IFS=$'\n'; echo "$*")
Đầu ra:
S
t
é
p
h
a
n
e
á
à
é
è
ë
ê
ế
e
Nếu bạn có thể thay đổi IFS và thay đổi các tham số vị trí, bạn cũng có thể tránh lệnh gọi shell phụ:
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
cập nhật ở đây là cách hacky | nhanh nhất | purBashBasing!
$ 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
cho nhiều điều tuyệt vời
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' ' ')
điều này sẽ phân chia từ của bạn và lưu trữ nó trong mảng var
.
for x in $(echo "$yourWordhere" | grep -o '.')
do
code to perform operation on individual character $x of your word
done