我正在根据下一行寻找客场联络线。到目前为止,我看到的唯一方法是创建一个 shell 脚本,该脚本将逐行读取并执行以下操作:
while read line
if $line does not start with "," and $curr_line is empty
store line in curr_line
if $line does not start with "," and $curr_line is not empty
flush $curr_line to file
store $line in $curr_line
if $line starts with "," append to $curr_file, flush to file empty curr_line
done < file
所以我试图了解是否可以使用 sed 甚至 grep 和重定向来实现。该文件的规则很简单。最多且只有一行以“,”开头的行需要附加到上一行。
前任:
line0
line1
line2
,line3
line4
line5
,line6
line7
,line8
line9
line10
line11
结果文件将是
line0
line1
line2,line3
line4
line5,line6
line7,line8
line9
line10
line11
答案1
我会做:
awk -v ORS= '
NR>1 && !/,/ {print "\n"}
{print}
END {if (NR) print "\n"}' < file
也就是说,如果当前行不以 开头,则仅打印分隔上一行的换行符,
。
任何状况之下,我不会使用while read
循环。
答案2
这是 的一个经典用例sed
,如中所述Sed 单行解释,第一部分:文件间距、编号以及文本转换和替换,40. 如果前一行以等号“=”开头,则在前一行后面追加一行。,
(对 for进行了明显的修改=
)
sed -e :a -e '$!N;s/\n,/,/;ta' -e 'P;D' file
line0
line1
line2,line3
line4
line5,line6
line7,line8
line9
line10
line11
答案3
您需要做的就是读取文件并删除逗号之前的所有换行符:
$ perl -0777pe 's/\n,/,/g' file
line0
line1
line2,line3
line4
line5,line6
line7,line8
line9
line10
line11
答案4
这是一个完美的的用例ex
。
如果您还没有听说过,ex
是 的前身vi
,例如vi
,它是由 POSIX 指定并且基本上*随处可用。
ex
实际上是为文件设计的编辑,但您也可以在不保存更改的情况下使用它。
打印更改,不保存到文件:
printf '%s\n' 'g/^,/-j!' %p | ex file.txt
进行更改并保存到文件:
printf '%s\n' 'g/^,/-j!' x | ex file.txt
解释:
我使用该printf
命令作为脚本文件编辑的包装器ex
。这种形式的优点是,在任何失败时(例如,您传递的命令不是真正的命令,或者您尝试寻址不存在的行号),该命令只是退出(不保存任何更改)而不是等待其他输入。
您可以通过运行命令本身来查看传递给printf
的确切命令:ex
printf
$ printf '%s\n' 'g/^,/-j!' %p
g/^,/-j!
%p
好吧,这些命令有什么作用?
嗯,g
是“全局”命令,它在“缓冲区”(文件)中与正则表达式匹配的所有行上运行以下命令^,
(行开头后跟逗号)。
本例中的命令是-j!
.是-
一个地址,表示在该地址上执行以下命令以前的行到当前行。 (换句话说,在这条线上前以逗号开头的行。)
j
用于“连接”,它将该行与下一行连接起来。感叹号 ( !
) 禁止使用空格字符来分隔原始行和与其连接的行。
%
是一个地址,意思是“整个缓冲区”,p
意思是“打印”。
x
表示保存更改并退出。
正如我所说,这是一个完美的的用例示例ex
。
*Windows 除外。 :P