我只是偶然发现在 bash 中,我们可以将命令分配给变量而不使用alias
.
g=date
$g
Mon Jun 27 13:00:40 MYT 2016
这样可行。这是另一个例子:
jj="ping yahoo.com"
$jj
PING yahoo.com (98.138.253.109) 56(84) bytes of data.
64 bytes from ir1.fp.vip.ne1.yahoo.com (98.138.253.109): icmp_seq=1 ttl=41 time=347 ms
64 bytes from ir1.fp.vip.ne1.yahoo.com (98.138.253.109): icmp_seq=2 ttl=41 time=345 ms
64 bytes from ir1.fp.vip.ne1.yahoo.com (98.138.253.109): icmp_seq=3 ttl=41 time=345 ms
我正在使用这个版本的bashbash --version GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
我调查过堆栈交换和tldp 吸收值,但没有发现我们可以这样做。那么这是 bash 的新功能还是被忽视的东西?这是否被考虑命令替换?
答案1
在交互式使用中,外壳从终端设备读取输入行。输入一行后,就是解析的通过分裂成代币(单词和运算符)。然后以特定顺序扩展或解析标记或单词。
注意:一般来说,通常最好参考规范的信息来源,例如项目文档或行业规范,而不是二手来源,例如高级 Bash 脚本指南、在线教程、书籍 - 甚至 Stack Exchange :)。此类二手资料对于用更简单的语言介绍和解释概念很有用,但它们通常并不旨在完整或取代官方文档。二手来源中的信息也可能已经过时。
在这种情况下,解析简单命令的 POSIX 规范指出
- 非变量赋值或重定向的词应扩展。如果扩展后仍有任何字段,则第一个字段应被视为命令名称,其余字段是命令的参数。
- 不是变量赋值或重定向的单词会被扩展(请参阅 Shell 扩展)。如果扩展后仍有任何单词,则第一个单词将被视为命令名称,其余单词将被视为参数。
答案2
这不是命令替换,而是多变的代换。您不是将命令分配给变量,而是分配一个字符串。该命令在您使用变量时运行,而不是在赋值时运行。
g=date
将字符串存储date
在变量中g
。如果您随后运行echo "$g"
,则会打印 的值g
,即date
(后跟换行符),因为 的值作为第一个参数g
传递给命令。echo
如果运行"$g"
,这会将字符串date
放在命令的第一个位置,因此它是命令名称。
随着$jj
,第二个因素开始发挥作用。因为变量扩展是在引号之外,所以“split+glob 运算符”应用于该值。在本例中,这意味着 的值jj
被分成两个以空格分隔的单词。因此,该单词ping
最终位于命令位置,并且该单词yahoo.com
是第一个参数。
答案3
这是预期的行为,并且多年来一直有效。它对于在脚本中构建命令很有用。
例如,我有时应该在将某些输入发送到管道之前对其进行解压缩(然后对输出进行压缩),但有时则不然。使用bash
:
if (( use_compression == 1 )); then
infilter='gzip -d -c'
outfilter='gzip -c'
else
infilter='cat'
outfilter='cat'
fi
$infilter "$indatafile" | somepipeline | $outfilter >"$outdatafile"
是命令替换吗?不。“命令替换”特指用$(...)
其输出内容替换反引号变体。
这是相反参数扩展,即简单地将参数替换为其值。这发生在命令实际执行之前,这就是它起作用的原因。
这意味着像下面这样的东西也可以在命令行上运行:
$ decompress='gzip -d -c'
$ ${decompress/g/gun/} filename >unzippedfilename
(这会执行gunzip
而不是gzip
)
编辑:关于别名。
手册bash
说:
对于几乎所有用途,别名都被 shell 函数取代。
... 并且我同意。
别名适合简短的内容,例如
alias ls="ls -F"
(这是我在自己的 shell 会话中拥有的唯一别名)
您可能不想在命令行上对“别名”命令使用参数扩展。如果没有其他原因的话,打字会让人感到脖子疼痛。参数扩展也不允许执行稍微复杂的任务,例如管道。
如果您定期执行中等复杂的操作,请改用 shell 函数。
以已接受的答案为例U&L问题(您在下面的评论中链接到):
alias my_File='ls -f | grep -v /'
这个别名显然有效,但是使用
my_File='ls -f | grep -v /'
$my_File
如果您随后尝试在命令行上用作命令,则该命令将不起作用(如该 U&L 线程中所解释的原因)。
使用 shell 函数,您还可以执行诸如传递参数之类的操作:
function my_File {
ls -l "$@" | fgrep -v '/'
}
$ my_File -iF symlink
84416642 lrwxr-xr-x 1 kk staff 4 Jun 27 09:03 symlink@ -> file
答案4
它只是使用 shell 变量,这个概念已经存在并像这样工作了几十年(毫不夸张)。
当您将变量放入命令行时,shell 会替换它,然后运行该命令,因此如果您的变量位于开头,那么它显然会被视为命令。