遇到特殊字符时将文件拆分为多个
Split file into multiple when special char met
我有一个主文件如下:
/* ------------- AAAAAAAA ------------- */
some
lines
here
/* ------------- BBBBBBBB ------------- */
more
things
/* ------------- CCCCCCCC ------------- */
there
a
few
more
lines
我的最终目标是创建一个只包含包含特定字符串的块的文件,例如,如果该字符串是 lines
,那么我将得到一个这样的输出文件:
/* ------------- AAAAAAAA ------------- */
some
lines
here
/* ------------- CCCCCCCC ------------- */
there
a
few
more
lines
为了达到我的 objective,我首先尝试通过 bock 将我的主文件拆分为子文件以获得类似
的内容
- 文件-1
- 文件-2[=44=]
- 文件-3
然后我计划检查每个文件,如果包含搜索到的字符串,那么我将它们追加回我的新主文件。
老实说,我不知道这是否是最好的方法,而且我的主文件中有 30139 行的 1600 多个块,因此需要解析很多。
但是,如果我保持这种方式来完成工作,我的代码仍然存在问题:
#!/bin/ksh
i=0
while IFS=\| read -r "line"; do
if [ `echo $line | grep '/* ------' | wc -l` -eq 1 ]; then
i=$((i+1))
fi
echo $line > "file-$i"
done <
由于每个块由 /* --------
分隔,如果我执行 echo $line
,输出将是我的根目录(/etc
、/tmp
等)而不是$line
本身。
所以我知道这是一个 2 个问题-post 但是因为第二个问题可以使用不同的方式来绕过脚本,所以它肯定是有联系的。
编辑:
解决方案必须在 korn shell 因为我不能在这台机器上安装任何东西
如果您不介意使用 Perl 那么有一个很好的 one-liner 可以让您轻松实现。
您唯一需要做的就是添加这样一行:
/* ------------- END ------------- */
在文件的最后。所以变成这样:
/* ------------- AAAAAAAA ------------- */
some
lines
here
/* ------------- BBBBBBBB ------------- */
more
things
/* ------------- CCCCCCCC ------------- */
there
a
few
more
lines
/* ------------- END ------------- */
现在借助这个 regex 模式:
\/\*.*?(?=\/\*)
您可以分别匹配每个部分。例如这部分:
/* ------------- AAAAAAAA ------------- */
some
lines
here
因此,如果您将结果存储在末尾的 array 中,您将得到一个包含 3 部分的数组。最终您可以在每个部分申请 lines
。如果找到,则会打印该部分。
单行
perl -ne 'BEGIN{$/=undef;}push(@arr,$&) while/\/\*.*?(?=\/\*)/smg;END{for (@arr){print if /lines/g }}' file
输出为:
/* ------------- AAAAAAAA ------------- */
some
lines
here
/* ------------- CCCCCCCC ------------- */
there
a
few
more
lines
如果你申请more
:
/* ------------- BBBBBBBB ------------- */
more
things
/* ------------- CCCCCCCC ------------- */
there
a
few
more
lines
基于@batMan 解决方案
命令行解决方案:
tr '\n' ';' < file | grep -Po '\/\*.*?(?=\/\*)' | grep lines | tr ';' '\n'
它的输出:
/* ------------- AAAAAAAA ------------- */
some
lines
here
/* ------------- CCCCCCCC ------------- */
there
a
few
more
lines
awk 中的另一个:
$ awk '
function dump() { # define a function to avoid duplicate code in END
if(b~/lines/) # if buffer has "lines" in it
print b # output and ...
b="" } # reset buffer
/^\/\*/ { dump() } # at the start of a new block dump existing buffer
{ b=b (b==""?"":ORS) [=10=] } # gather buffer
END{ dump() } # dump the last buffer also
' file
/* ------------- AAAAAAAA ------------- */
some
lines
here
/* ------------- CCCCCCCC ------------- */
there
a
few
more
lines
使用 awk
awk -v RS="/[*]" '/lines/{printf "/*"[=10=]}' file
输出:
/* ------------- AAAAAAAA ------------- */
some
lines
here
/* ------------- CCCCCCCC ------------- */
there
a
few
more
lines
当你真的想使用while read
结构时,尽量避免额外的文件和系统调用。
matched=0
all=
while IFS= read -r line; do
if [[ ${line} =~ "/* ----"* ]]; then
if [ ${matched} -eq 1 ]; then
printf "%s\n" "${all}"
fi
all=
matched=0
fi
all="${all}${line}
"
if [[ "${line}" =~ line ]]; then
matched=1
fi
done < <(cat mainfile; echo "/* ---- The End --- */" )
我有一个主文件如下:
/* ------------- AAAAAAAA ------------- */
some
lines
here
/* ------------- BBBBBBBB ------------- */
more
things
/* ------------- CCCCCCCC ------------- */
there
a
few
more
lines
我的最终目标是创建一个只包含包含特定字符串的块的文件,例如,如果该字符串是 lines
,那么我将得到一个这样的输出文件:
/* ------------- AAAAAAAA ------------- */
some
lines
here
/* ------------- CCCCCCCC ------------- */
there
a
few
more
lines
为了达到我的 objective,我首先尝试通过 bock 将我的主文件拆分为子文件以获得类似
的内容- 文件-1
- 文件-2[=44=]
- 文件-3
然后我计划检查每个文件,如果包含搜索到的字符串,那么我将它们追加回我的新主文件。
老实说,我不知道这是否是最好的方法,而且我的主文件中有 30139 行的 1600 多个块,因此需要解析很多。
但是,如果我保持这种方式来完成工作,我的代码仍然存在问题:
#!/bin/ksh
i=0
while IFS=\| read -r "line"; do
if [ `echo $line | grep '/* ------' | wc -l` -eq 1 ]; then
i=$((i+1))
fi
echo $line > "file-$i"
done <
由于每个块由 /* --------
分隔,如果我执行 echo $line
,输出将是我的根目录(/etc
、/tmp
等)而不是$line
本身。
所以我知道这是一个 2 个问题-post 但是因为第二个问题可以使用不同的方式来绕过脚本,所以它肯定是有联系的。
编辑:
解决方案必须在 korn shell 因为我不能在这台机器上安装任何东西
如果您不介意使用 Perl 那么有一个很好的 one-liner 可以让您轻松实现。
您唯一需要做的就是添加这样一行:
/* ------------- END ------------- */
在文件的最后。所以变成这样:
/* ------------- AAAAAAAA ------------- */
some
lines
here
/* ------------- BBBBBBBB ------------- */
more
things
/* ------------- CCCCCCCC ------------- */
there
a
few
more
lines
/* ------------- END ------------- */
现在借助这个 regex 模式:
\/\*.*?(?=\/\*)
您可以分别匹配每个部分。例如这部分:
/* ------------- AAAAAAAA ------------- */
some
lines
here
因此,如果您将结果存储在末尾的 array 中,您将得到一个包含 3 部分的数组。最终您可以在每个部分申请 lines
。如果找到,则会打印该部分。
单行
perl -ne 'BEGIN{$/=undef;}push(@arr,$&) while/\/\*.*?(?=\/\*)/smg;END{for (@arr){print if /lines/g }}' file
输出为:
/* ------------- AAAAAAAA ------------- */
some
lines
here
/* ------------- CCCCCCCC ------------- */
there
a
few
more
lines
如果你申请more
:
/* ------------- BBBBBBBB ------------- */
more
things
/* ------------- CCCCCCCC ------------- */
there
a
few
more
lines
基于@batMan 解决方案
命令行解决方案:
tr '\n' ';' < file | grep -Po '\/\*.*?(?=\/\*)' | grep lines | tr ';' '\n'
它的输出:
/* ------------- AAAAAAAA ------------- */
some
lines
here
/* ------------- CCCCCCCC ------------- */
there
a
few
more
lines
awk 中的另一个:
$ awk '
function dump() { # define a function to avoid duplicate code in END
if(b~/lines/) # if buffer has "lines" in it
print b # output and ...
b="" } # reset buffer
/^\/\*/ { dump() } # at the start of a new block dump existing buffer
{ b=b (b==""?"":ORS) [=10=] } # gather buffer
END{ dump() } # dump the last buffer also
' file
/* ------------- AAAAAAAA ------------- */
some
lines
here
/* ------------- CCCCCCCC ------------- */
there
a
few
more
lines
使用 awk
awk -v RS="/[*]" '/lines/{printf "/*"[=10=]}' file
输出:
/* ------------- AAAAAAAA ------------- */
some
lines
here
/* ------------- CCCCCCCC ------------- */
there
a
few
more
lines
当你真的想使用while read
结构时,尽量避免额外的文件和系统调用。
matched=0
all=
while IFS= read -r line; do
if [[ ${line} =~ "/* ----"* ]]; then
if [ ${matched} -eq 1 ]; then
printf "%s\n" "${all}"
fi
all=
matched=0
fi
all="${all}${line}
"
if [[ "${line}" =~ line ]]; then
matched=1
fi
done < <(cat mainfile; echo "/* ---- The End --- */" )