我想要一种从参考管理器 Zotero 导出笔记的简单方法。我首先选择多个笔记并将它们拖到一个空白文本文件中。我还希望实现笔记的“原子性”,因此我需要分割生成的文本文件,其中包含由破折号线分隔的各个部分中的各个笔记。然后,我想使用我给每个注释的标题来命名新文件,即:用每个部分的第一行重命名。我想将这些新文件保存为 markdown 文件。
我整理的脚本由网络上的贡献者对每个功能的建议组成。在与与我有类似用例的同事共享脚本之前,我试图确保我正确理解脚本中的命令。我对“head”命令中“$f”周围需要引号的理解(从阅读吉尔斯对另一个问题的回答 - 请参阅下面的参考链接)似乎不正确。我尝试了不带引号的脚本并得到了相同的结果。是否真的不需要双引号,因为“$f”出现在赋值的右侧?它们在那里只是因为默认情况下使用双引号比在不需要它们时记住它们更容易吗?任何进一步的解释将不胜感激。
Notes_test.txt 中的输入文件示例如下
This is note 1
It has some notes
--------------------------------------------------
This is note 2
It has some more notes
输出应该是两个文件:
This is note 1.md
This is note 2.md
这是我在命令行上使用的脚本:
csplit Notes_test.txt -f_ -z -b'%03d.md' /--------------------------------------------------/1 {*} && sed -i '/./,$!d' *.md && for f in *.md
do
f1=$(head -n1 "$f")
mv -n "$f" "$f1.md"
done
到目前为止,这是我对命令的理解:
-fPREFIX 使用 PREFIX 作为输出文件名前缀。在这种情况下,指定了下划线:“_”,我认为它只是一个占位符。
-z 禁止生成零长度输出文件。我认为这是必要的,因为否则 csplit 将在每次运行结束时通过拆分原始文件生成一个空文件。
-bSuffix 使用SUFFIX 作为输出文件名后缀。在这种情况下:“md”
%03d 将 3 位数字作为文件名的占位符。根据 FelixJN 的建议,我在 3 之前添加了 0。
/------------------------------------------------- -/1 指定分割的分隔符,分割位于“-”行下方 2 行(计数从 0 开始)。
{*} 告诉 bash 运行分割直到文件末尾。正如 Felix 指出的,“{n}”是要执行的分割数。在这种情况下,“*”意味着尽可能多地进行。
&& 表示在前一条命令完成的情况下执行后一条命令
sed -i 指示 sed 对具有特定后缀 '/./,$!d' 的文件进行操作 意思是“删除文件头部的空行” 再次感谢 Felix 的解释,这是为了指定 sed 工作的范围: A ”。”表示任何字符,因此它指定文档中出现的第一个字符。由于空行没有任何字符,因此我们需要应用负号“!”定义范围后。该范围由模式 /“start”/,/“end”/ 定义,以在字符串“start”和“end”之间应用命令。 $ 指的是最后一行,因此范围是文档中所有非空行。要应用否定,请使用“!”意思是“NOT”,即告诉 sed 选择与先前范围相反的值。在这种情况下,第一行之前的所有行都可以包含任何字符。然后“d”删除这些行。
*.md 的意思是“任何带有后缀 .md 的名称”
f1=$(head -n1 "$f") 意思是:定义f1为文件的第一行(“head”的意思是“第一行”)。这是通过使用变量符号“$”定义“f1”来完成的,“f1”将是新文件名(减去后缀)的占位符(在脚本的下一行中)。 “head”是一个 bash 命令,通常输出每个文件的前 10 行: head [OPTION]... [FILE]... 选项 -n1 指定仅输出一行。这里,“$f”指定“所有文件”,而不是指定特定的文件。 “$f”周围需要引号,以便忽略空格(否则 $f 使用空格作为字段分隔符并进一步拆分文件 - 请参阅下面的参考链接)。
mv -n "$f" "$f1.md" 意思是:将每个文件重命名为“f1.md”
bash 命令“mv”采用选项和参数:mv [OPTION]... [-T] SOURCE DEST 即:“将 SOURCE 重命名为 DEST”。 -n 选项代表 --no-clobber “不覆盖现有文件”。我认为这只是为了防止存在具有相同第一行的文件(注释)。
看https://www.tutorialspoint.com/unix_commands/csplit.htm和 coreutils 用于类 UNIX 操作干,位于https://www.gnu.org/software/coreutils/manual/coreutils.pdf 和https://www.howtoforge.com/linux-csplit-command/Q2.如何使用正则表达式分割文件?和为什么我的 shell 脚本会因为空格或其他特殊字符而卡住? 什么时候需要双引号?
答案1
由于我认为您的理解没有任何问题,因此我将重点关注这sed
部分。
范围
sed
可以在一个范围内运行命令,例如从第 11 行到第 20 行用 a 替换(s
替换) an A
(即一行中的第一个),B
如下所示:
sed '11,20s/A/B/'
范围也可以通过模式匹配来定义,以在字符串和/start/,/end/
之间应用命令。start
end
对于您的情况,我们有/./,$
。
A.
表示任何字符,空行没有任何字符,因此仅当行不为空时才适用。
$
仅引用最后一行,因此我们将对整个文档执行此操作,但跳过开头的空行。
现在!
开始发挥作用,这意味着“NOT”,即选择与之前范围相反的值。在这种情况下,第一行之前的所有行都带有一个字符。
d
然后删除这些行。
'{*}'
中的另一条评论csplit
。'{n}'
是要执行的分割数,星号仅表示尽可能多。您也只能分裂 5 次。
%3d
我建议不要使用来%03d
表示零填充的三位数,它使排序更容易。