簡體   English   中英

: <<'END' 如何在 bash 中創建多行注釋塊?

[英]How does : <<'END' work in bash to create a multi-line comment block?

我找到了一個關於如何在 bash 腳本中評論的好答案( @sunny256 ):

 #!/bin/bash echo before comment : <<'END' bla bla blurfl END echo after comment

END分隔符周圍的''很重要,否則塊內的內容(例如$(command)將被解析並執行。

這可能很難看,但它有效,我很想知道它的含義。 誰能簡單解釋一下? 我確實已經找到了一個解釋:它是無操作或真實的。 但無論如何,調用 no-op 或 true 對我來說是沒有意義的......

恐怕這種解釋不那么“簡單”而更“徹底”,但我們開始吧。

注釋的目標是作為代碼解釋或執行的文本。

最初,UNIX shell本身沒有注釋語法。 然而,它確實有一個空命令:曾經是磁盤上的一個實際二進制程序, /bin/: :),它忽略它的參數並且除了指示調用 shell 成功執行之外什么都不做。 實際上,它是true的同義詞,看起來像標點符號而不是單詞,因此您可以在腳本中添加這樣的一行:

: This is a comment

這不是一個傳統的評論。 它仍然是 shell 執行的實際命令。 但既然命令什么都不,肯定它已經足夠接近了:任務完成了! 正確的?

問題是該行仍然被視為一個命令,而不僅僅是作為一個命令運行。 最重要的是,詞法分析——參數替換、分詞等——仍然發生在那些注定要被忽略的論點上。 這樣的處理意味着您冒着在“注釋”中出現語法錯誤的風險,從而使整個腳本崩潰:

 : Now let's see what happens next
 echo "Hello, world!"
 #=> hello.sh: line 1: unexpected EOF while looking for matching `''

這個問題導致引入了真正的注釋語法:現在熟悉的# (它首先在 BSD 創建的 C shell 中引入)。 #到行尾的所有內容都被 shell 完全忽略,所以你可以放任何你喜歡的東西,而不用擔心語法有效性:

 # Now let's see what happens next
 echo "Hello, world!"
 #=> Hello, world!

這就是Shell 獲得注釋語法的方式。

但是,您正在尋找 C 或 Java 中由/* (並由*/終止)引入的那種多行(塊)注釋。 不幸的是,shell 根本沒有這樣的語法。 注釋掉連續行塊的正常方法——也是我推薦的方法——只是在每行前面放一個# 但這無疑不是一種特別“多線”的方法。

由於 shell 支持多行字符串文字,您可以使用:將這樣的字符串作為參數:

: 'So
this is all
a "comment"
'

但這與單行:具有所有相同的問題。 您還可以在每行的末尾使用反斜杠來構建一個帶有多個參數而不是一個長字符串的長命令行,但這比在前面放置#更煩人,而且更脆弱,因為尾隨空格會破壞行繼續.

您找到的解決方案使用所謂的here-document 語法some-command <<whatever導致以下文本行 - 從命令之后的行開始,直到但不包括僅包含文本whatever下一行 - 被讀取並作為標准輸入提供給some-command 這是“Hello, world”的另一個 shell 實現,它利用了這個特性:

cat <<EOF
Hello, world
EOF

如果你將cat替換為我們的老朋友: ,你會發現它不僅忽略了它的參數,還忽略了它的輸入:你可以給它任何你想要的東西,它仍然什么都不做(並且仍然表明它什么也沒做成功地)。

但是,here-document 的內容會經過字符串處理。 因此,就像單行:注釋一樣,here-document 版本在不應該成為可執行代碼的內部存在語法錯誤的風險:

#!/bin/sh -e 
: <<EOF
(This is a backtick: `)
EOF
echo 'In modern shells, $(...) is preferred over backticks.'
#=> ./demo.sh: line 2: bad substitution: no closing "`" in `

如您找到的代碼所示,解決方案是在介紹此處文檔的行(例如<<'EOF' )上引用文檔結尾“哨兵”( EOFEND或其他)。 這樣做會導致 here-document 的整個正文被視為文字文本 - 不會發生參數擴展或其他處理。 相反,文本原封不動地饋送到命令中,就好像它是從文件中讀取的一樣。 因此,除了只包含哨兵的一行之外,here-document 可以包含任何字符:

#!/bin/sh -e
: <<'EOF'
(This is a backtick: `)
EOF
echo 'In modern shells, $(...) is preferred over backticks.'
#=> In modern shells, $(...) is preferred over backticks.

(值得注意的是,你引用哨兵的方式並不重要 - 你可以使用<<'EOF'<<E"OF" ,甚至<<EO\F ; 都具有相同的結果。這是不同的從 here-documents 在其他一些語言(例如 Perl 和 Ruby)中的工作方式來看,根據引用標記的方式,對內容的處理方式不同。)

盡管有上述任何一項,我強烈建議您只在要注釋掉的每一行的前面加上一個# 任何體面的代碼編輯器都會使該操作變得容易 - 即使是普通的舊vi - 好處是沒有人閱讀您的代碼將不得不花費精力來弄清楚到底發生了什么事情,這些事情畢竟是為了他們的利益而編寫的文檔。

它被稱為Here Documen t。 它是一個代碼塊,可讓您將命令列表發送到另一個命令或程序

<<后面的字符串是確定塊結束的標記。 如果您向 no-op 發送命令,則不會發生任何事情,這就是您可以將其用作注釋塊的原因。

這是heredoc語法。 這是一種定義多行字符串文字的方法。

正如您鏈接中的答案所解釋的那樣, END 周圍的單引號會禁用插值,類似於單引號字符串禁用常規 bash 字符串中的插值的方式。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM