我有一个日志文件(来自客户)。 18演出。该文件的所有内容都在一行。 我想在logstash中读取该文件。但是因为记忆我得到了问题。该文件逐行读取,但遗憾的是它全部在1行。
我尝试将文件拆分成行,以便logstash可以处理它(文件有一个简单的json格式,没有嵌套对象)我想让每个json在一行中,在}
分割,替换为{ {1}}:
}\n
但是sed -i 's/}/}\n/g' NonPROD.log.backup
被杀了 - 我还认为也是因为记忆。我该如何解决这个问题?我可以让sed
使用除行之外的其他数据块来操作文件吗?我知道默认情况下sed
会逐行读取。
答案 0 :(得分:6)
以下仅使用内置于shell中的功能:
#!/bin/bash
# as long as there exists another } in the file, read up to it...
while IFS= read -r -d '}' piece; do
# ...and print that content followed by '}' and a newline.
printf '%s}\n' "$piece"
done
# print any trailing content after the last }
[[ $piece ]] && printf '%s\n' "$piece"
如果您已将logstash配置为从TCP端口读取(使用14321
作为下面的任意示例),您可以运行thescript <NonPROD.log.backup >"/dev/tcp/127.0.0.1/14321"
或类似的,并且您可以 - 无需双原始输入文件在磁盘上的可用空间,因为到目前为止需要的其他答案。
答案 1 :(得分:3)
使用RT
的GNU awk:
$ printf 'abc}def}ghi\n' | awk -v RS='}' '{ORS=(RT?"}\n":"")}1'
abc}
def}
ghi
与其他问题:
$ printf 'abc}def}ghi\n' | awk -v RS='}' -v ORS='}\n' 'NR>1{print p} {p=$0} END{printf "%s",p}'
abc}
def}
ghi
我决定使用此命令生成的输入文件测试所有当前发布的功能和执行时间的解决方案:
awk 'BEGIN{for(i=1;i<=1000000;i++)printf "foo}"; print "foo"}' > file1m
这就是我得到的:
1)awk(上面的两个awk脚本都有类似的结果):
time awk -v RS='}' '{ORS=(RT?"}\n":"")}1' file1m
得到预期的输出,时间=
real 0m0.608s
user 0m0.561s
sys 0m0.045s
2)shell loop:
$ cat tst.sh
#!/bin/bash
# as long as there exists another } in the file, read up to it...
while IFS= read -r -d '}' piece; do
# ...and print that content followed by '}' and a newline.
printf '%s}\n' "$piece"
done
# print any trailing content after the last }
[[ $piece ]] && printf '%s\n' "$piece"
$ time ./tst.sh < file1m
得到预期的输出,时间=
real 1m52.152s
user 1m18.233s
sys 0m32.604s
3)tr+sed:
$ time tr '}' '\n' < file1m | sed 's/$/}/'
未产生预期的输出(在文件末尾添加了不受欢迎的}
),timing =
real 0m0.577s
user 0m0.468s
sys 0m0.078s
通过调整来删除最终不受欢迎的}
:
$ time tr '}' '\n' < file1m | sed 's/$/}/; $s/}//'
real 0m0.718s
user 0m0.670s
sys 0m0.108s
4)fold+sed+tr:
$ time fold -w 1000 file1m | sed 's/}/}\n\n/g' | tr -s '\n'
得到预期的输出,时间=
real 0m0.811s
user 0m1.137s
sys 0m0.076s
$ cat tst2.sh
mkdir tmp$$
pwd="$(pwd)"
cd "tmp$$"
split -b 1m "${pwd}/${1}"
sed -i 's/}/}\n/g' x*
cat x*
rm -f x*
cd "$pwd"
rmdir tmp$$
$ time ./tst2.sh file1m
得到预期的输出,时间=
real 0m0.983s
user 0m0.685s
sys 0m0.167s
答案 2 :(得分:2)
您可以通过tr
运行它,然后在每行末尾重新放置结束括号:
$ cat NonPROD.log.backup | tr '}' '\n' | sed 's/$/}/' > tmp$$
$ wc -l NonPROD.log.backup tmp$$
0 NonPROD.log.backup
43 tmp10528
43 total
(我的测试文件只有43个括号。)
答案 3 :(得分:1)
你可以:
split -b 1m file.log
sed 's/}/}\n/g' x*
sed
的输出以将它们组合回单件这样做的缺点是存储空间增加了一倍。
答案 4 :(得分:0)
fold
$ fold -w 1000 long_line_file | sed 's/}/}\n\n/g' | tr -s '\n'