我有很长的一行,我想在纯文本的单行上每 4 个字符插入一个空格,以使其更易于阅读,最简单的方法是什么?我也应该能够从管道输入线路。例如
echo "foobarbazblargblurg" | <some command here>
给出
foob arba zbla rgbl urg
答案1
使用 sed 如下:
$ echo "foobarbazblargblurg" | sed 's/.\{4\}/& /g'
foob arba zbla rgbl urg
答案2
您可以使用以下简单示例:
$ echo "foobarbazblargblurg" | fold -w4 | paste -sd' ' -
foob arba zbla rgbl
答案3
仅在 bash 中,无外部命令:
str="foobarbazblargblurg"
[[ $str =~ ${str//?/(.)} ]]
printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"
或者作为单行管道版本:
echo foobarbazblargblurg |
{ IFS= read -r str; [[ $str =~ ${str//?/(.)} ]]; \
printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"; }
其工作方式是将字符串的每个字符转换为“(.)”以进行正则表达式匹配并使用 进行捕获=~
,然后从数组中输出捕获的表达式 BASH_REMATCH[]
,并根据需要进行分组。保留前导/尾随/中间空格,删除周围的引号"${BASH_REMATCH[@]:1}"
以省略它们。
这里它被包装在一个函数中,这个函数将处理它的参数,或者如果没有参数则读取 stdin:
function fmt4() {
while IFS= read -r str; do
[[ $str =~ ${str//?/(.)} ]]
printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"
done < <( (( $# )) && printf '%s\n' "$@" || printf '%s\n' $(< /dev/stdin) )
}
$ echo foobarbazblargblurg | fmt4
foob arba zbla rgbl urg
您可以轻松参数化计数以相应地调整格式字符串。
添加尾随空格,printf
如果有问题,请使用两个而不是一个:
printf "%s%s%s%s" "${BASH_REMATCH[@]:1:4}"
(( ${#BASH_REMATCH[@]} > 5 )) && printf " %s%s%s%s" "${BASH_REMATCH[@]:5}"
第一个printf
打印(最多)前 4 个字符,第二个有条件地打印所有其余字符(如果有),并用前导空格分隔各组。该测试针对 5 个元素而不是 4 个元素来说明第 0 个元素。
笔记:
- shell
printf
可以%c
用来代替%s
,%c
(也许)使意图更清晰,但它不是多字节字符安全的。如果您的 bash 版本支持,则以上内容都是多字节字符安全的。 - shell
printf
重用其格式字符串,直到用完参数,因此它一次只会吞噬 4 个参数,并处理尾随参数(因此不需要边缘情况,不像这里的其他一些答案,这些答案可能是错误的) BASH_REMATCH[0]
是整个匹配的字符串,所以只输出从索引1开始的- 使用
printf -v myvar ...
而不是存储到变量myvar
(受通常的读取循环/子shell行为的影响) printf "\n"
如果需要的话添加
zsh
如果您使用数组match[]
而不是,则可以使上述工作正常进行BASH_REMATCH[]
,并从所有索引中减去 1,因为zsh
不会在整个匹配中保留 0 元素。
答案4
grep
这是使用和 的示例xargs
:
$ echo "foobarbazblargblurg" | grep -o .... | xargs
foob arba zbla rgbl