假设我有一个包含以下内容的shell脚本:
echo "This is a single-line text"
echo "
Examples: 1
2
3
4
"
现在我想要的是从每行的开头去掉多余的空间:
我不是使用sed
的专家,所以到目前为止我尝试过的是sed -i 's|^ ||' file
,但这也与多行引用块匹配,我不希望它这样做
sed -i 's|^ ||' file
最终为:
echo "This is a single-line text"
echo "
Examples: 1
2
3
4
"
但我预计它会是这样的:
echo "This is a single-line text"
echo "
Examples: 1
2
3
4
"
那么,我怎么能让sed忽略这样的模式呢?我也可以接受任何基于awk
的解决方案。
谢谢。
假设:
- 倒数第二行由
4 spaces
+"
组成;这些空格不应被删除,因为它们位于带引号的文本块内 - 最后一行仅由
4 spaces
组成,并将被修剪为空行 - 不必担心任何边缘案例(参见KamilCuk的评论(
一个基于跟踪我们遇到的双引号("
(数量的awk
想法:
awk '
/^ / { if ( qtcnt % 2 == 0 ) # if current line starts with 4 spaces and we
# have seen an even number of double quotes
# prior to this line (ie, we are outside
# of a double quoted string) then ...
$0=substr($0,5) # remove the 4 spaces from the current line
}
{ print $0 } # print the current line
{ n=split($0,arr,""") # split the current line on double quotes and
# get a count of the number of fields
if ( n >=1 ) # if number of fields >= 1 (ie, line contains
# at least one double quote) then ...
qtcnt += n - 1 # increment our quote counter
}
' indent.dat
注意:
- 在以下情况下,这将错误地计算双引号
- 转义双引号(
"
( - 单引号双引号(
awk -F'"' ...
( - 出现在注释中的双引号(
# this is a double quote (")
(
如果print
行更改为print "."$0"."
(使用句点作为视觉分隔符(,则会生成以下内容:
.echo "This is a single-line text".
..
.echo ".
.Examples: 1.
. 2.
. 3.
. 4.
. ".
..
按编码(无周期(生成以下内容:
echo "This is a single-line text"
echo "
Examples: 1
2
3
4
"
注意:最后一行为空/空白
使用GNU awk for gensub((和RT:
$ cat tst.awk
BEGIN { RS="""; ORS="" }
NR%2 { $0 = gensub(/(^|n)[[:blank:]]+/,"\1","g") }
{ print gensub(/n[[:blank:]]+$/,"n",1) RT }
$ awk -f tst.awk file
echo "This is a single-line text"
echo "
Examples: 1
2
3
4
"
或使用任何POSIX awk:
$ cat tst.awk
BEGIN { RS=ORS=""" }
NR > 1 { print prev }
NR%2 {
sub(/^[[:blank:]]+/,"")
gsub(/n[[:blank:]]+/,"n")
}
!(NR%2) {
sub(/n[[:blank:]]+$/,"n")
}
{ prev = $0 }
END { printf "%s", prev }
$ awk -f tst.awk file
echo "This is a single-line text"
echo "
Examples: 1
2
3
4
"
注意:任何解决方案都是脆弱的,除非你为shell语言编写一个解析器,它可以理解"
何时在字符串、脚本、转义等中。