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

0 shell bash io-redirection

我知道简单的<是接受来自文件的输入的命令, 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岁那样解释吗?谢谢。

ilk*_*chu 6

这三件事<,<<<(是不同的运算符。运算符中不能有空格,但在某些情况下,它们之间需要空格以帮助 shell 正确识别您的意思。

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

例如:

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

  • cat << EOF产生“单词cat”、“heredoc 运算符”、“单词EOF”和

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

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

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

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


也就是说,您的最后一个命令sshpass -f<(printf '%s\n' $PASSWORD) 应该以与 , 相同的方式cat<filename工作,实际上它确实对我有用:

$ sshpass -f<(echo password) ssh foo@localhost 'echo hi'
hi
Run Code Online (Sandbox Code Playgroud)

随着set -x我们看到了实际运行的命令,是

sshpass -f/dev/fd/63 ssh foo@localhost 'echo hi'
Run Code Online (Sandbox Code Playgroud)

即用文件名替换进程替换,然后才能sshpass看到它。但是,对于某些程序,-f foo和之间可能存在差异-ffoo,但这与解析 shell 运算符的方式不同。