传递输入时,哪种方法更好?
> echo 'test' | base64
dGVzdAo=
> base64 <<< 'test'
dGVzdAo=
同样对于变量,应该使用哪种方法?
> t='test'
> echo "$t" | base64
dGVzdAo=
> base64 <<< "$t"
dGVzdAo=
答案1
<<<
zsh
是here-string,是here-document (以及 Unix 端口)在 90 年代初引入的缩写形式rc
,此后被复制(带有变体)到许多其他 shell。
它的实现方式与此处文档相同。在包括zsh
和在内的大多数 shell 中bash
,这是通过删除临时文件来实现的,Bourne shell(在 70 年代末引入了此处文档的 shell)就是这样做的。
当你这样做时:
cmd <<< 'something'
shell 做了类似的事情:
file=$(mktemp)
printf 'something\n' > "$file"
{
rm -f -- "$file" && cmd
} < "$file"
(当然,所有mktemp
, printf
,rm
都是在内部完成的,而不执行这些命令)。
一些 shell 使用管道和单独的进程(可以是分叉命令或小此处文档/字符串的主 shell 进程)来提供数据。某些 shell 可能会恢复使用/dev/null
空的此处文档(此处字符串不能为空,除非rc
不添加换行符)。
使用临时文件的实现有几个优点。
- 没有分叉进程。
- 输入是可查找的(该命令可以在其输入中来回读取数据,以在不同的位置再次读取数据,而当其输入是管道时则无法执行此操作)。不过,您不能在可移植
sh
脚本中依赖它。
一些缺点:
- 除了 in 之外
zsh
,内容不能包含 NUL 字节 - 除了 in 之外
rc
,不可能提供不以换行符结尾的输入 - 临时文件创建可能会失败(例如当没有剩余空间
$TMPDIR
或umask
某些实现限制太多时)。 - 数据存储在永久存储器中。即使文件在被删除之前被删除
read
,数据也可能最终被提交到磁盘,这意味着如果有人能够获得磁盘,则可以将其恢复。
在:
printf '%s\n' "$something" | cmd
(这里使用printf
而不是echo
asecho
不能用于任意数据)。
我们有两个进程同时运行,一个进程通过管道将输出提供给另一个进程。当cmd
是内置命令或复合命令或函数时,使用zsh
或 AT&Tksh
或bash -o lastpipe
,该命令在当前 shell 中运行,但否则在子进程中运行,因此类似的操作echo x | read var
不起作用。
这样做的一些优点:
- 是便携式的(与
<<<
,<<
是便携式相反) - 没有
<<<
上面提到的缺点 - 要在 shell 之外的 shell 中提供 NUL 字节
zsh
(zsh
是唯一可以将 NUL 字节传递给内置命令的 shell),您可以执行以下操作printf '\0' | cmd
:
缺点:
- 额外的进程以及在某些 shell 中的子进程中运行的事实
cmd
,如上所述 - 输入不可查找。
请注意,如果您想要 的 base64 编码test
,那就是:
printf test | base64
或者
printf %s "$data" | base64
对于任意数据。
您的为您提供了 的 base64 编码test<newline>
。