我对脚本编写很陌生,所以我很感谢任何帮助。我有一个文本文件,在某些情况下可能会很长,文本行的每个部分大约有 6/7 行长。它是一个日志文件,每个部分都以时间戳一词开头。每段行之间有一个空行。每个剖面行都以分号结束。
timestamp=201706291035.....;
line 2;
line 3;
line 4;
line 5;
line 6;
line 7;
timestamp=201706291038.....;
line 2;
line 3;
line 4;
line 5;
line 6;
我需要能够在一行中将每个部分提取到另一个文本文件中。最好没有最后一个分号。
timestamp=201706291035.....;line 2;line 3;line 4;line 5;line 6;line 7
timestamp=201706291038.....;line 2;line 3;line 4;line 5;line 6
这些信息足以找到解决方案吗?
这是一个直接的例子:
时间戳=2017-06-28-01.01.35.080576;
事件状态=0;
用户ID=用户1;
authid=用户1;
应用程序ID = 10.10.10.10.11111.12345678901;
应用程序名称=GUI;
时间戳=2017-06-28-01.01.36.096486;
事件状态=0;
用户ID=用户1;
authid=用户1;
应用程序ID = 10.10.10.10.11111.12345678901;
应用程序名称=GUI;
语句文本=从数据库中选择 table.field, table.field, table.field where table.field = value
运行脚本 @steeldriver 后,源文件和目标文件看起来相同。
答案1
这可以使用惯用的 awk 来完成,如下所示:
awk '$1=$1' RS= OFS= infile
输出:
timestamp=201706291035.....;line 2;line 3;line 4;line 5;line 6;line 7;
timestamp=201706291038.....;line 2;line 3;line 4;line 5;line 6;
解释
这里装了很多东西。基本上有三个步骤:
- 首先,根据记录分隔符 (
RS
) 将输入拆分为记录。 - 每条记录根据字段分隔符 (
FS
) 拆分为多个字段。 - 打印时,输出字段分隔符 (
OFS
) 用作字段分隔符。
当 awk 解析其输入时,有几个隐式规则在起作用。读取数据时,一次一条记录,记录之间用 分隔RS
(默认为\n
)。当RS
为空时,如上例所示,空行分隔记录。因此,每个部分都作为记录读入。
为了强制awk
替换FS
为,OFS
我们将第一个字段设置$1
为其自身。
编辑
正如所指出的钢铁起子,OP想要删除尾随的分号。无耻抄袭:
awk '{ sub(/;$/,"",$NF); $1=$1 } 1' RS= OFS= infile
答案2
这可以通过以下方式完成:
perl -lF';\n?' -00ne '$,=";"; print @F' yourfile
输出
timestamp=201706291035.....;line 2;line 3;line 4;line 5;line 6;line 7
timestamp=201706291038.....;line 2;line 3;line 4;line 5;line 6
在职的
Perl 选项
a)
-l
=> ORS="\n" + RS = "\n"b)
-F';\n?'
=> 将使 FS 成为分号,后跟可选的换行符。c)
-00
=> 将使 RS= 从而启用段落模式。d)
-n
=> 将启用隐式文件读入+显式打印。Main:
$,=;
会给OFS加上分号,是根据@F
当前记录划分出来的字段。$_
FS
答案3
如果时间戳之前有空行,您可以使用简单的
perl -pe 'chomp unless /^$/'
如果换行符不存在,则需要记住上一行。
perl -pe 'chomp; print "\n" if $. > 1 && /^timestamp=/; print }{ print "\n"'
答案4
只是因为,这是一种方法sed
以这句话为我们的起点Peter Krumins 的 Sed 行话解释,第一部分:文件间距、编号以及文本转换和替换
如果一行以反斜杠“\”结尾,则将其追加到下一行。
sed -e :a -e '/\\$/N; s/\\\n//; ta'
第一个表达式 ':a' 创建一个命名标签“a”。第二个表达式查看当前行是否以反斜杠“\”结尾。如果存在,它将使用“N”命令将其与其后面的行连接起来。然后使用“s/\\n//”命令删除连接行之间的斜杠和换行符。如果替换成功,我们分支到表达式的开头并再次执行相同的操作,希望我们可能有另一个反斜杠。如果替换不成功,则该行不会以反斜杠结尾,我们会将其打印出来。
替换\\
为;
并调整替换以保留;
但删除前导空格,我们得到
$ sed -e :a -e '/;$/N; s/\n *//; ta' infile
timestamp=201706291035.....;line 2;line 3;line 4;line 5;line 6;line 7;
timestamp=201706291038.....;line 2;line 3;line 4;line 5;line 6;
关闭!现在我们想要挤出空白行 - 我们可以通过测试模式是否可以做到这一点结束在换行符中(即附加行为空),如果是则打印取决于换行符然后丢弃模式:
$ sed -e :a -e '/;$/N; /\n$/{P;d;}; s/\n *//; ta' infile
timestamp=201706291035.....;line 2;line 3;line 4;line 5;line 6;line 7;
timestamp=201706291038.....;line 2;line 3;line 4;line 5;line 6;
现在我们只需要修剪掉尾随的;
.一种方法是在将行附加到模式空间时删除每个行;
,然后在丢弃换行符时重新插入它:
$ sed -e :a -e '/;$/{s///;N;}; /\n$/{P;d;}; s/\n */;/; ta' infile
timestamp=201706291035.....;line 2;line 3;line 4;line 5;line 6;line 7
timestamp=201706291038.....;line 2;line 3;line 4;line 5;line 6
最后一个;
不会被重新插入,因为我们已经用 吃掉了换行符,所以{P;d;}
替换s//\n /;/
不会被应用。