这些特殊的左 < 是什么以及为什么空格很重要?

这些特殊的左 < 是什么以及为什么空格很重要?

我知道最简单的<是一个接受文件输入的命令 grep search-word <filename grep search-word < filename ,在这种情况下空格并不重要。

但在这两种情况下,只有一种语法有效,在其他地方放置空格不起作用:

(gdb) r < <(python -c "print('\x44\x43\x42\x41')")作品; (gdb) r << (python -c "print('\x44\x43\x42\x41')")不起作用; (gdb) r<<(python -c "print('\x44\x43\x42\x41')")不起作用;

或这里

sshpass -f <(printf '%s\n' $PASSWORD)作品; sshpass -f < (printf '%s\n' $PASSWORD)不起作用; sshpass -f<(printf '%s\n' $PASSWORD)不起作用;

这是为什么?有人能像我 5 岁一样解释一下吗?谢谢。

答案1

<<<和三个事物<(是不同的运算符。运算符内不能有空格,但在某些情况下,它们之间需要空格以帮助 shell 正确识别您的含义。

词法分析器的通常行为是吃掉产生有效运算符的最长字符集,然后将表示该运算符的标记返回给解析器,解析器然后处理该语言的实际语法。

例如:

  • cat < filename生成三个标记“单词cat”、“输入重定向运算符”、“单词filename”。

  • cat << EOF产生“单词cat”、“heredoc 运算符”、“单词EOF”,以及

  • cat < < EOF会产生四个标记“单词cat”、“输入重定向运算符”、“输入重定向运算符”、“单词EOF”,但这在语法上没有意义,并且会产生错误。

  • cat<filename其行为与第一个相同,因为<除非引用,否则该字符不能成为单词的一部分,因此标记会在此处中断。

类似地,<(是进程替换的开始,但< (只是两个运算符<,并且(因为空格将它们分开。并且,由于最长前缀匹配,<<(here-doc 运算<<符后跟(and不是重定向运算符<后跟进程替换的开始,尽管这可能是更有用的解释。

采用最长前缀的行为在其他语言中也很常见。例如,在 C 中,与(或)i+++a相同,对于,您需要第一个 后面的空格。两者都是有效的表达方式,只是含义不同。在 C++ 中,长期以来,您必须将嵌套模板编写为,因为如果没有空格,则会被视为不相关的右移运算符,而不是模板语法所需的两个 。i ++ + ai++ + ai + ++a+vector<vector<int> >>>>


也就是说,你的最后一个命令,sshpass -f<(printf '%s\n' $PASSWORD) 应该工作,与 一样cat<filename,而且,实际上它对我有用:

$ sshpass -f<(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 运算符的解析方式不同。

相关内容