给予字符串:
foo='Hello \
World! \
x
we are friends
here we are'
在\
字符之后或之前,还有制表符与空格混合。
我想只用空格替换空格,制表符和斜杠。我尝试过:
echo "$foo" | tr "[\s\t]\\\[\s\t]\n\[\s\t]" " " | tr -s " "
返回:
Hello World! x we are friend here we are
我需要的结果是:
Hello World! x
we are friends
here we are
有什么想法,小费或技巧吗? 我能在一个命令中得到我想要的结果吗?
答案 0 :(得分:3)
以下单行提供了所需的结果:
echo "$foo" | tr '\n' '\r' | sed 's,\s*\\\s*, ,g' | tr '\r' '\n'
Hello World!
we are friends
here we are
说明:
tr '\n' '\r'
从输入中删除换行符,以避免换行符的特殊sed行为。
sed 's,\s*\\\s*, ,g'
将带有嵌入\的空格转换为一个空格。
tr '\r' '\n'
放回未更改的换行符。
答案 1 :(得分:1)
尝试如下:
#!/bin/bash
foo="Hello \
World!"
echo $foo | sed 's/[\s*,\\]//g'
答案 2 :(得分:1)
如果您只想打印输出,只需:
foo='Hello \
World!'
bar=$(tr -d '\\' <<<"$foo")
echo $bar # unquoted!
Hello World!
如果你想在存储在变量中的空格时挤压空格,那么其中一个:
bar=$(tr -d '\\' <<<"$foo" | tr -s '[:space:]' " ")
bar=$(perl -0777 -pe 's/\\$//mg; s/\s+/ /g' <<<"$foo")
perl版本的优点是它只删除行连续反斜杠(在行尾)。
请注意,当您使用双引号时,shell会处理行继续(斜杠后没有空格的正确行:
$ foo="Hello \
World"
$ echo "$foo"
Hello World
所以在这一点上,为时已晚。
如果使用单引号,则shell不会解释行继续,
$ foo='Hello \
World!
here we are'
$ echo "$foo"
Hello \
World!
here we are
$ echo "$foo" | perl -0777 -pe 's/(\s*\\\s*\n\s*)/ /sg'
Hello World!
here we are
答案 3 :(得分:1)
foo='Hello \
World! \
x
we are friends
here we are'
如果使用双引号,则shell会将\
解释为行继续符。切换到单引号会保留字面反斜杠。
我在World!
之后添加了一个反斜杠来连续测试多个反斜杠行。
sed -r ':s; s/( )? *\\ *$/\1/; Te; N; bs; :e; s/\n *//g' <<< "$foo"
输出:
Hello World! x
we are friends
here we are
这是做什么的?在伪代码中,您可以将其读作:
while (s/( )? *\\ *$/\1/) { # While there's a backslash to remove, remove it...
N # ...and concatenate the next line.
}
s/\n *//g # Remove all the newlines.
详细说明,这是它的作用:
:s
是一个标有s
的分支,用于“开始”。s/( )? *\\ *$/\1/
替换反斜杠及其周围的空格。如果有一个空格,则通过捕获( )?
留下一个空格。Te
会跳转到标签e
。N
连接以下行,包括换行符\n
。bs
跳回到开头。这样我们就可以使用反斜杠处理多个连续的行。:e
是标有e
的“end”分支。s/\n *//g
删除了第4步中的所有额外换行符。它还会从后续行中删除前导空格。请注意T
是GNU扩展。如果您需要在另一个版本的sed中使用它,则需要使用t
。这可能需要额外的b
标签或两个。
答案 4 :(得分:1)
您可以使用read
循环来获得所需的输出。
arr=()
i=0
while read line; do
((i++))
[ $i -le 3 ] && arr+=($line)
if [ $i -eq 3 ]; then
echo ${arr[@]}
elif [ $i -gt 3 ]; then
echo $line
fi
done <<< "$foo"
答案 5 :(得分:1)
使用awk
:
$ echo "$foo"
Hello \
World! \
x
we are friends
here we are
$ echo "$foo" | awk '{gsub(/[[:space:]]*\\[[:space:]]*/," ",$0)}1' RS= FS='\n' ORS='\n\n'
Hello World! x
we are friends
here we are
.
$ echo "$foo" |
awk '{
gsub(/[[:space:]]*\\[[:space:]]*/," ",$0)
a[++i] = $0
}
END {
for(;j<i;) printf "%s%s", a[++j], (ORS = (j < NR) ? "\n\n" : "\n")
}' RS= FS='\n'
Hello World! x
we are friends
here we are
答案 6 :(得分:1)
sed是一个很好的工具,可以在一行上进行简单的替换,但对于其他任何东西只需使用awk。这使用GNU awk进行多字符RS(其他awks RS='\0'
适用于不包含NUL字符的文本文件):
$ echo "$foo" | awk -v RS='^$' -v ORS= '{gsub(/\s+\\\s+/," ")}1'
Hello World! x
we are friends
here we are
答案 7 :(得分:0)
使用诸如extended globbing,parameter expansion之类的基础知识......但它可能同样丑陋
foo='Hello \
World!'
shopt -s extglob
echo "${foo/+( )\\*( )$'\n'/ }"
Hello World!
答案 8 :(得分:0)
据我所知,你想删除尾随空格后跟一个反斜杠转义的换行符?
在这种情况下,请使用正则表达式( ) *\\\n
进行搜索并替换为\1