我有以下文本文件:
#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) grep
ping 所有未注释的行加上前面的信息一和 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