Sed

幫我理解一個使用 csplit 和 sed 的腳本

  • September 11, 2021

我想要一種從參考管理器 Zotero 導出筆記的簡單方法。我首先選擇多個筆記並將它們拖到一個空白文本文件中。我還希望實現筆記的“原子性”,因此我需要將生成的文本文件拆分,其中包含由破折號分隔的部分中的各個筆記。然後我想使用我給每個註釋的標題來命名新文件,即:用每個部分的第一行重命名。我想將這些新文件保存為降價文件。

我編寫的腳本是由網路上的貢獻者對這些功能中的每一個的建議組成的。在與與我有類似案例的同事分享之前,我試圖確保我正確理解了腳本中的命令。我的理解(通過閱讀 Gilles 對另一個問題的回答 - 請參閱下面的參考連結)需要在 " $ f" in the “head” command does not seem to be correct. I tried the script without the quotes and got the same result. Are the double quotes not really needed because " $ 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 之前添加了零。

/—————————————————- -/1 指定拆分的分隔符,拆分在“-”行下方 2 行(計數從 0 開始)。

{} 告訴 bash 執行拆分直到文件結束。正如 Felix 指出的那樣,“{n}”是要執行的拆分數。在這種情況下,“”表示盡可能多地做。

&& 表示在上一條命令完成的情況下執行下面的命令

sed -i 指示 sed 對帶有特定後綴“/./”的文件進行操作, $ !d’ means “remove blank lines at head of file” Thanks to Felix again for explaining that that this is to specify the range on which sed works: A “.” means any character, so it specifies the first character that occurs in the document. Since empty lines do not have any characters, we will need to apply the negative “!” after defining the range. The range is defined by the pattern /“start”/,/“end”/ to apply the command between the strings “start” and “end”. $ 指最後一行,所以範圍是文件中所有非空行。應用否定使用“!” 意思是“NOT”,即告訴 sed 選擇與前一個範圍相反的值。在這種情況下,第一行之前的所有行都帶有任何字元。“d” 然後刪除這些行。

*.md 表示“任何名稱後綴為 .md”

f1 = $ (head -n1 " $ f") 表示:將 f1 定義為文件的第一行(“head”表示“第一行”)。這是通過使用變數符號“ $ " to define “f1” which will be a placeholder (in the next line of the script) for the new file names (minus suffix). “head” is a bash command that normally outputs the first 10 lines of each file: head [OPTION]… [FILE]… The option -n1 specifies to output one line only. Here, instead of specifying a particular FILE, " $ f" 指定“所有文件”。“周圍的引號” $ f" are needed so that whitespace is ignored (otherwise $ 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 以了解https://www.gnu.org/software/coreutils/manual/coreutils.pdfhttps://www .howtoforge.com/linux-csplit-command/ Q2.如何使用正則表達式拆分文件?為什麼我的 shell 腳本會因空格或其他特殊字元而窒息什麼時候需要雙引號?

由於我認為您的理解沒有任何問題,因此我將重點介紹該sed部分。

範圍

sed可以在一個範圍內執行命令,例如用從第 11 行到第 20 行替換(s替換)一個A(即一行中的第一個)B看起來像:

sed '11,20s/A/B/'

範圍也可以通過模式匹配來定義,以在字元串和/start/,/end/之間應用命令。start``end

在您的情況下,我們有/./,$.

A.表示任何字元,空行沒有任何字元,所以它只適用於非空行。 $只是指最後一行,所以我們會對整個文件執行此操作,但會跳過開頭的空行。

現在!開始起作用,這意味著NOT,即選擇與先前範圍相反的範圍。在這種情況下,第一行之前的所有行都帶有一個字元。

d然後刪除這些行。


中的另一條評論'{*}'。是要執行的拆分數,星號表示盡可能多。你也只能分裂5次。csplit``'{n}'

而不是%3d,我建議使用%03d零填充的三位數字,它使排序更容易。

引用自:https://unix.stackexchange.com/questions/667835