我知道简单的<是接受来自文件的输入的命令,
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岁那样解释吗?谢谢。
这三件事<,<<和<(是不同的运算符。运算符中不能有空格,但在某些情况下,它们之间需要空格以帮助 shell 正确识别您的意思。
词法分析器的通常行为是吃掉产生有效运算符的最长字符集,然后将表示该运算符的标记返回给解析器,解析器然后处理语言的实际语法。
例如:
cat < filename产生三个标记“单词cat”、“输入重定向运算符”、“单词filename”。
cat << EOF产生“单词cat”、“heredoc 运算符”、“单词EOF”和
cat < < EOF将产生四个标记“单词cat”、“输入重定向运算符”、“输入重定向运算符”、“单词EOF”,但这在语法上毫无意义并给出错误。
cat<filename行为与第一个相同,因为<除非引用,否则字符不能成为单词的一部分,因此标记在那里中断。
类似地,<(是进程替换的开始,但< (只是两个操作符<,(因为空格将它们打断。并且,由于最长前缀匹配,<<(here-doc 运算符<<后跟 the(而不是重定向运算符<后跟进程替换的开始,即使这可能是更有用的解释。
采用最长前缀的行为在其他语言中也很常见。例如,在 C 中,i+++a与i ++ + 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 运算符的方式不同。