我正在编写一个应该要比较安全的shell脚本,即不通过命令参数传递安全数据,并且最好不使用临时文件。如何将变量传递到命令的标准输入中?
如果不可能,那么如何正确地使用临时文件完成这个任务?
在Bash中将一个值传递给标准输入非常简单:
your-command <<< "$your_variable"
始终确保您在变量表达式周围加上引号!
请注意,这可能只适用于
bash
,在sh
中可能无法正常工作。
<<<
操作符并不保证可用性,因为它们不在 POSIX 标准中,就我所知。只要你的运行环境是 bash
,这个操作符可以按期望工作。我提到这点是因为 OP 提到了“shell”,而非特指 bash
。虽然 OP 标记了问题的标签为 bash
,所以这仍然是一个可接受的答案。 - J. M. Beckerprintf '%s\n' "$var"
与 echo "$var"
输出的结果相同,但是前者在 var=-en
的情况下不会出错,而且甚至不需要 bash。请注意,此处仅为翻译,无其他返回信息。 - Camilo Martinecho "$your_variable" | command1 | command2
那样直观。在这种情况下,使用here strings的语法会是什么呢? - patricknelson<<< "$your_variable" command1 | command2
。 - Martinecho
像这样简单的代码可以顺利完成任务:
echo "$blah" | my_cmd
需要注意的是,如果$blah
包含-n
、-e
、-E
等内容,或者包含反斜杠(bash的echo
副本在默认情况下保留文字反斜杠,但即使未使用-e
选项,如果启用了可选的XSI扩展,它也会将其视为转义序列并替换为相应的字符),则此方法可能无法正常工作。
printf
printf '%s\n' "$blah" | my_cmd
这种方法没有上述缺点:所有可能的 C 字符串(不包含 NULs 的字符串)都会被原样打印。
printenv blah | my_cmd
? - mallwright(cat <<END
$passwd
END
) | command
cat
并不是必须的,但它有助于更好地组织代码,并允许您将更多命令用括号作为输入到您的命令中。
$passwd
中包含空格。 - PoltoS请注意,'echo "$var" | command
' 操作意味着标准输入仅限于被回显的行。如果您还希望连接终端,则需要更高级的操作:
{ echo "$var"; cat - ; } | command
( echo "$var"; cat - ) | command
这意味着第一行或几行将是$var
的内容,而其余部分将来自于cat
读取的标准输入。如果命令没有执行任何太复杂的操作(例如尝试打开命令行编辑器或像vim
一样运行),那么这应该没问题。否则,您需要变得非常高级 - 我认为expect
或其派生版本可能比较适合。cat -
会继续从键盘读取,直到遇到EOF或中断,因此您需要通过键入control-D来告诉它EOF。 - Jonathan Lefflercat
,就像第一行一样。或者您可以使用cat
列出文件。如果您想让命令读取终端输入,则必须告诉它何时已经到达输入的末尾。或者您可以使用( echo "$var"; sed /quit/q - ) | command
;这将一直持续到您键入包含“quit”的行为止。您可以无限创意地处理它。请注意,有一个旧的城市传说,说有一个程序在用户开始使用厄瓜多尔时停止工作。他们会输入首都基多的名称,然后程序退出。 - Jonathan Lefflerecho "$LIST" | head -n1
可以正常工作,但 echo "$LIST" | sed 1q
却不能? - Gert Cuykens这种强大且便携的方法已经出现在评论中了。它应该是一个独立的回答。
printf '%s' "$var" | my_cmd
或者printf '%s\n' "$var" | my_cmd
注:
printf
比echo
更好,原因在这里:为什么printf
比echo
更好?printf "$var"
是错误的。第一个参数是格式字符串,在其中各种序列如%s
或\n
会被解释。要正确传递变量,它不能被解释为格式。通常变量不包含尾随换行符。前面的命令(使用%s
)将变量按原样传递。然而,处理文本的工具可能会忽略或抱怨不完整的行(参见为什么文本文件要以换行符结尾?)。因此,您可能需要后面的命令(使用%s\n
),它将一个换行符附加到变量的内容中。非显然的事实:
<<<"$var" my_cmd
)确实附加了一个换行符。my_cmd
的标准输入非空,即使变量为空或未定义。foo1=-; foo2='"'; foo3=\!; cat<<<"$foo1"; cat<<<"$foo2"; cat<<<"$foo3"
在我的环境下运行良好。这三个 "
到底是做什么用的?据我所知,你只是在前后添加了一个空字符串。 - phk"""foo"""
与"foo"
的处理方式是完全相同的。""
只是一个空的引号对——在没有任何内容的情况下开始和结束一个带引号的字符串;因此,你可以将"$your_variable"
与前面和后面的空引号串联起来。 - Charles Duffy!
的行为不遵循我上面描述的规则?因为历史扩展发生在常规解析之前;这是一个非常混乱的功能,如果一开始就禁用它,每个人都会更好。 - Charles Duffy请注意,Here Strings 似乎只适用于 Bash,因此为了提高可移植性,建议使用原始的 Here Documents 功能,如 PoltoS's answer 所述:3.6.7 Here Strings
A variant of here documents, the format is:
<<< word
The word is expanded and supplied to the command on its standard input.
( cat <<EOF
$variable
EOF
) | cmd
(cmd <<EOF
$variable
EOF
)
(
和 )
,除非你希望将其进一步重定向到其他命令。试试这个:
echo "$variable" | command
echo
正在运行,那么 $variable
的内容不会出现在 ps -u
的输出中吗? - user283145echo
是一个内置命令,因此在ps中没有进程可以显示。 - unbeliecho "$variable"
更好。 - Jonathan Leffler如果您从重复的页面来到这里,您可能是一个初学者,尝试做类似以下的事情:
"$variable" >file
或者
"$variable" | wc -l
显然你想表达的是类似于
echo "$variable" >file
echo "$variable" | wc -l
(真正的初学者也会忘记引号;通常使用引号,除非你有特定的理由省略它们,至少在你理解引用之前。)
wc
用法”。 - tripleee$variable
包含一个有效的命令,比如文本echo
或git-commit
,那么"$variable"
不是语法错误(尽管通常不要将命令存储在变量中,请参见https://mywiki.wooledge.org/BashFAQ/050)。 - tripleee
$PATH
?以便将cat
替换为/bin/cat "$@" | tee /attacker/can/read/this/file
。 - 12431234123412341234123variable=$("$something" | command)
,而您想要的是variable=$(echo "$something" | command)
。 - tripleee