将命令分配给没有别名的变量

将命令分配给没有别名的变量

我只是偶然发现在 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 规范指出

  1. 非变量赋值或重定向的词应扩展。如果扩展后仍有任何字段,则第一个字段应被视为命令名称,其余字段是命令的参数。

Bash 手册中有关简单命令扩展的部分还指出

  1. 不是变量赋值或重定向的单词会被扩展(请参阅 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 会替换它,然后运行该命令,因此如果您的变量位于开头,那么它显然会被视为命令。

相关内容