Bash

這些特殊的左 < 是什麼以及為什麼空格很重要?

  • April 11, 2021

我知道簡單&lt;的是接受來自文件的輸入的命令 grep search-word &lt;filename grep search-word &lt; filename ,在這種情況下空格無關緊要。

但是在這兩種情況下,只有一種語法有效,將空格放在其他地方不起作用:

(gdb) r &lt; &lt;(python -c "print('\x44\x43\x42\x41')")作品; (gdb) r &lt;&lt; (python -c "print('\x44\x43\x42\x41')")不工作; (gdb) r&lt;&lt;(python -c "print('\x44\x43\x42\x41')")不工作;

或在這裡

sshpass -f &lt;(printf '%s\n' $PASSWORD)作品; sshpass -f &lt; (printf '%s\n' $PASSWORD)不工作; sshpass -f&lt;(printf '%s\n' $PASSWORD)不工作;

這是為什麼?有人可以像我5歲那樣解釋嗎?謝謝。

這三個東西&lt;,&lt;&lt;&lt;(是不同的運算符。運算符中不能有空格,但在某些情況下,它們之間需要空格以幫助 shell 正確辨識您的意思。

詞法分析器的通常行為是吃掉產生有效運算符的最長字元集,然後將表示該運算符的標記返回給解析器,然後解析器處理語言的實際語法。

例如:

  • cat &lt; filename產生三個標記“單詞cat”,“輸入重定向運算符”,“單詞filename”。
  • cat &lt;&lt; EOF產生“單詞cat”、“heredoc 運算符”、“單詞EOF”和
  • cat &lt; &lt; EOF會產生四個標記“單詞cat”、“輸入重定向運算符”、“輸入重定向運算符”、“單詞EOF”,但這在語法上沒有意義並給出錯誤。
  • cat&lt;filename行為與第一個相同,因為&lt;除非引用,否則該字元不能成為單詞的一部分,因此標記在那里中斷。

同樣,&lt;(是程序替換的開始,但&lt; (只是兩個運算符&lt;,並且(因為空格將它們打斷。而且,由於最長前綴匹配,&lt;&lt;(here-doc 運算符&lt;&lt;後面是 the(不是重定向運算符&lt;後面是程序替換的開始,即使這可能是更有用的解釋。

採用最長前綴的行為在其他語言中也很常見。例如,在 C 中,與(或)i+++a相同,對於,您需要在第一個 之後的空格。兩者都是有效的表達方式,它們只是意味著不同的東西。在 C++ 中,很長時間以來,您必須將嵌套模板編寫為,因為沒有空格,將被視為不相關的右移運算符,而不是模板語法所需的 two 。i ++ + a``i++ + a``i + ++a``+``vector&lt;vector&lt;int&gt; &gt;``&gt;&gt;``&gt;


也就是說,您的最後一個命令sshpass -f&lt;(printf '%s\n' $PASSWORD) 應該以與 相同的方式起作用cat&lt;filename,並且實際上它確實對我有用:

$ sshpass -f&lt;(echo password) ssh foo@localhost 'echo hi'
hi

我們set -x看到實際執行的命令是

sshpass -f/dev/fd/63 ssh foo@localhost 'echo hi'

即用文件名替換程序替換,在sshpass看到它之前。-f foo但是,對於某些程序,和之間可能存在差異-ffoo,但這與 shell 運算符的解析方式不同。

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