如何将变量的值传递给命令的标准输入?


105

我正在写一个应该在某种程度上安全的shell脚本,即不要通过命令的参数传递安全数据,最好不要使用临时文件。如何将变量传递给命令的标准输入?或者,如果不可能,如何正确使用临时文件执行此类任务?


攻击者可以改变$PATH吗?这样cat可以替换为/bin/cat "$@" | tee /attacker/can/read/this/file
12431234123412341234123'7

Answers:


74

简单的事情如下:

echo "$blah" | my_cmd

7
当心变量中的空格:echo "$blah"更好。
乔纳森·莱夫勒

13
让我们来看看你如何处理blah=-nblah=-e...利用printf来代替。unix.stackexchange.com/questions/65803/…–
卡米洛·马丁

1
这看起来像是脆弱且容易出错,不是吗?
ThorSummoner

19
6年后,如果我可以删除此答案,我会(但是我不能,因为它已经被接受了……)
奥利弗·查尔斯沃思

1
@OliverCharlesworth,为什么不编辑使用printf '%s\n' "$blah"呢?有了这一更改(避免了echo规范中的许多陷阱,在Unix和Linux上,Stephane的出色答案详细地解释了“ 为什么printfecho?更好,或者在echo规范的“应用程序使用”部分中进行了简要介绍),这是一个完美的选择合理的答案。
Charles Duffy

192

stdinbash中向传递值很简单:

your-command <<< "$your_variable"

始终确保在变量表达式两边加上引号!

请注意,这可能仅在中bash起作用而在中不起作用sh


39
<<<据我所知,herestrings 不能保证可用,它们不是基于POSIX的。只要您仅在中运行它们,它们就会按预期工作bash。我只提到它,因为他们说OP是“壳”而不是“重击”。尽管他确实用bash... 标记了问题,所以这显然还是可以接受的答案。
JM Becker 2012年

尽管可能是这种情况,但是如果使用此echo方法,由于创建了管道,敏感信息很可能更容易泄漏。herestring命令将完全由处理bash,尽管在这种情况下(如前所述),您最好知道它可以在bash上运行,否则由于不支持herestrings而产生的任何错误消息也会泄漏上述信息。
史蒂文·卢

@StevenLu Wait,echo是内置的。那里没有管道,对吗?它是Unix,但不能那么多Unix
卡米洛·马丁

4
@StevenLu printf '%s\n' "$var"产生的结果与@StevenLu 产生的结果相同,echo "$var"但不会中断,var=-en甚至不需要bash。
卡米洛·马丁

1
还要注意,对于此处的字符串,在字符串后添加了换行符。
pdr

19

请注意,“” echo "$var" | command操作表示标准输入仅限于回显的行。如果您还希望连接终端,则需要更高级:

{ echo "$var"; cat - ; } | command

( echo "$var"; cat -   ) | command

这意味着第一行将是的内容,$var其余的将来自于cat读取其标准输入。如果该命令没有做任何花哨的事情(尝试打开命令行编辑或像vim执行命令那样运行),那将很好。否则,您需要真正看中-我认为expect或其一种衍生产品可能是合适的。

命令行符号实际上是相同的-但是括号中的第二个分号是必需的,而括号中则不需要。


( echo "$LIST"; cat - ) | sed 1q这对我有用,但是运行此脚本时我需要按ctrl d?
Gert Cuykens,2012年

是; 将cat -继续从键盘,直到EOF或中断阅读,因此,您需要通过键入控制d EOF告诉它。
乔纳森·勒夫勒

有没有办法解决EOF?SED需要猫
格特Cuykens

cat如第一行所示,如果您不需要终端输入,则根本不需要使用。或者您可以使用cat列出文件。或者...如果要让命令读取终端输入,则必须在到达输入末尾时告诉它。或者你可以用( echo "$var"; sed /quit/q - ) | command; 这一直持续到您键入包含“ quit”的行。您将如何无休止地创新。当用户开始使用厄瓜多尔时,请注意该程序停止运行的古老的城市传说。他们输入大写字母Quito的名称,程序退出。
乔纳森·莱夫勒

既然你这么说,那好吧。但是,为什么不echo "$LIST" | sed 1q | ...呢?这一切都取决于您要做什么。该<<EOF符号应在文件下方某处的行首处要求EOF。我认为我不会使用它-但我仍然不确定您要达到的目标。一个简单的echo "$LIST" | commandecho $LIST | command可能在实践中就足够了(重要的是,您必须了解两者之间的区别的重要性)。
乔纳森·勒夫勒

16

我喜欢Martin的答案,但是根据变量中的内容,它存在一些问题。这个

your-command <<< """$your_variable"""

如果变量包含“或!”会更好


4
但为什么?另外,我无法重现任何问题:foo1=-; foo2='"'; foo3=\!; cat<<<"$foo1"; cat<<<"$foo2"; cat<<<"$foo3"对我来说效果很好。这三个到底是做"什么的?抱歉,您只是在添加和添加一个空字符串。
phk

尝试一些真实的东西。就像您的命令是ssh somehost。而您的变量是一个shell脚本。
罗伯特·雅各布斯

16
(cat <<END
$passwd
END
) | command

cat是不是真的需要,但它有助于更好地结构中的代码,并允许您在括号中使用更多的指令输入到你的命令。


但这种方法可以让你多行传递给你的命令,也可以在空间$passwd
PoltoS

4
到目前为止,这是最好的答案,不会将变量内容泄漏到管道或进程监听中。
user2688272

8

按照Martin的回答,有一个bash功能叫做Here Strings(它本身是更广泛支持的Here Documents功能的一种变体)。

http://www.gnu.org/software/bash/manual/bashref.html#Here-Strings

3.6.7此处字符串

这里文档的一种变体,格式为:

<<< word

该单词将被扩展并通过其标准输入提供给命令。

请注意,此处字符串似乎仅适用于bash,因此,为了提高可移植性,按照PoltoS的回答,您可能最好使用原始的此处文档功能:

( cat <<EOF
$variable
EOF
) | cmd

或者,上述的一个更简单的变体:

(cmd <<EOF
$variable
EOF
)

您可以省略(),除非您希望将其进一步重定向到其他命令。


5

这种健壮和可移植的方式已经出现在评论中。它应该是一个独立的答案。

printf '%s' "$var" | my_cmd

要么

printf '%s\n' "$var" | my_cmd

笔记:

  • 胜于echo,原因在这里:为什么printf胜于echo
  • printf "$var"是错的。第一个参数是格式,在该格式中会解释%s\n表示各种序列。要正确传递变量,不得将其解释为格式。
  • 通常,变量不包含尾随换行符。前一个命令(带有%s)按原样传递变量。但是,使用文本的工具可能会忽略或抱怨行不完整(请参阅为什么文本文件应以换行符结尾?)。因此,您可能需要后面的命令(带有%s\n),该命令将换行符附加到变量的内容中。非显而易见的事实:

    • Bash(<<<"$var" my_cmd)中的字符串确实会添加换行符。
    • 任何追加换行符的方法都会导致非空的stdin为my_cmd,即使变量为空或未定义。

4

试试这个:

echo "$variable" | command

但是内容$ variable不会在ps -u运行echo 的输出中显示吗?

2
不,不会。echo是内置的,因此没有以ps显示的过程
unbeli 2011年

2
当心变量中的空格:echo "$variable"更好。
乔纳森·莱夫勒

没错,bash会吃掉两个空格,更聪明的弹壳不会
吃掉

-1

做就是了:

printf "$my_var" | my_cmd

如果var不包含空格,则可以省略引号。
如果使用bash,那么您也可以执行以下操作:

echo -n "$my_var" | my_cmd

避免在不使用-n的情况下使用echo,因为它将通过管道在末尾添加换行符。


1
如果$ my_var是不起作用%s,printf将不打印任何内容。my_var="%s"; printf "$my_var"; -也许试试printf "%s" "$my_var" | my_cmd
hanshenrik '18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.