从长文件中提取文本行

从长文件中提取文本行

我有以下文本文件:

#unimportant comment
#possible more unimportant comments
#info1 info2 info3 ,importantname1
importanttext1
#info1 info2 info3 ,importantname2
importanttext2
#info1 info2 info3 ,importantname3
importanttext3

我想将每个文件分解为单独的文件。我真正需要的是提取未注释的网址,保留注释是可选的。我希望每个文件都被命名为 importantname1.txt 或每个注释行末尾逗号后面附加 .txt 的名称

所以 importantname1.txt 将包含以下内容:

importanttext1 

或者可能

#info1 info2 info3 ,importantname1
importanttext1

因此该行将被提取并使用注释后的文件名保存,并在本例中附加 .txt 文件名 importantname1.txt

需要对示例文件中的每组行执行此操作。保留注释并不重要,但我需要它可以编写脚本。我还需要考虑标题中未知数量的注释行。注释行始终位于每个 importanttextX 行之前

答案1

尝试:

awk -F, '/^#/{f=$NF".txt";cmt=$0; next} {printf "%s\n%s\n",cmt,$0 >f; close(f)}' file

例子

应用于您的示例输入:

$ awk -F, '/^#/{f=$NF".txt";cmt=$0; next} {printf "%s\n%s\n",cmt,$0 >f; close(f)}' file

上述运行后,目录下有以下文件:

$ ls
file  importantname1.txt  importantname2.txt  importantname3.txt

新文件的内容是:

$ cat importantname1.txt 
#info1 info2 info3 ,importantname1
importanttext1
$ cat importantname2.txt 
#info1 info2 info3 ,importantname2
importanttext2
$ cat importantname3.txt 
#info1 info2 info3 ,importantname3
importanttext3

怎么运行的

awk 逐行读取输入文件。我们的脚本将这些行分类为注释或非注释。对于注释行,将保存文件名和注释。对于非注释,将创建并打印一个新文件

  • `-F,

    这告诉 awk 使用逗号作为输入的字段分隔符。这样,文件名将始终是最后一个字段。

  • /^#/{f=$NF".txt";cmt=$0; next}

    如果一行以 开头#,我们将最后一个字段$NF加上.txt作为文件名保存f。整个注释行保存为cmt.然后我们告诉 awk 跳过其余命令并跳转到该next行重新开始。

  • printf "%s\n%s\n",cmt,$0 >f; close(f)

    对于非注释行,我们将最后看到的注释cmt和当前行打印$0到最后看到的文件名 中f。然后我们关闭 的文件句柄f

防止错误的文件名

如果要用作文件名的字段包含/,操作系统会将文件名解释为包含目录。为了避免这种情况,我们可以将 all 替换/-using gsub(/\//, "-", f),如下所示:

awk -F, '/^#/{f=$NF".txt";gsub(/\//, "-", f); cmt=$0; next} {printf "%s\n%s\n",cmt,$0 >f; close(f)}' file

答案2

grep和的组合csplit可以完成这项工作,方法是 a) grepping 所有未注释的行加上前面的信息一和 b) 根据信息注释行分割输出:

grep -v -B1 '^#' file | csplit -z - '/^#/' '{*}'

即不-v提取开头有# 的行^#,而是提取这些行前面的一行-B1。然后-在行开头的每个 # 处拆分传入的管道输入,忽略空文件-z并尽可能频繁地执行此操作{*}

重命名必须是一个单独的步骤(csplit将输出自动命名为 xx00、xx01 ... - 分别使用-f-b选项更改前缀和后缀)

#/bin/bash
for f in xx* ; do
   mv "$f" "$( sed -n '2p' "$f" )".txt
done

相关内容