变量赋值后在同一行运行命令是否可以通过 shell 移植?

变量赋值后在同一行运行命令是否可以通过 shell 移植?

是否有任何标准涵盖在同一行上进行变量赋值后运行命令的可移植性?

APPLE="cider" echo hi

这样的东西有多便携?它在哪里有效,在哪里无效?

另外:我的 shell 脚本以 #!/bin/sh 开头,如果这有什么区别的话。

答案1

只要您使用 POSIX 兼容的 shell,就可以。

来自shell命令语言的POSIX定义(相关点以粗体显示)

“简单命令”是一系列可选变量赋值和重定向,以任何顺序,可选地跟随单词和重定向,由控制操作符终止。

当需要执行给定的简单命令时(即,当任何条件结构(例如 AND-OR 列表或 case 语句)未绕过该简单命令时),以下扩展、赋值和重定向均应从命令文本的开头到结尾:

  1. 被识别为变量赋值的单词或根据重定向Shell 语法规则保存以供步骤 3 和 4 中的处理。

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

  3. 重定向应按中所述执行重定向

  4. 每个变量赋值都应在赋值之前进行扩展,以进行波形符扩展、参数扩展、命令替换、算术扩展和引号删除。

在前面的列表中,对于特殊内置实用程序的处理,步骤 3 和 4 的顺序可以颠倒;看特殊的内置实用程序

如果没有命令名结果,变量赋值将影响当前的执行环境。否则,变量分配应针对命令的执行环境导出,并且不应影响当前的执行环境(特殊内置除外)。


此外,是#!/bin/sh很重要的。从POSIX 定义sh:

sh 实用程序是一种命令语言解释器,它将执行从命令行字符串、标准输入或指定文件读取的命令。申请应确保要执行的命令用描述的语言表达外壳命令语言

所以基本上它说sh必须遵循我们上面介绍的规则。

因此,只要您使用的是 POSIX 兼容的操作系统,就可以了。

答案2

回答第二个问题,不完全(炮弹数量为令人难以置信

% for sh in dash ksh93 mksh rc fish bash zsh csh tcsh jsh; do
printf '%s\n' "$sh: $($sh -c 'var=foo echo hi')"
done

dash: hi
ksh93: hi
mksh: hi
rc: hi
fish: Unknown command “var=foo”. Did you mean “set var foo”? For information on assigning values to variables, see the help section on the set command by typing “help set”
Standard input: var=foo echo hi
                ^
fish:
bash: hi
zsh: hi
var=foo: Command not found.
csh:
var=foo: Command not found.
tcsh:
jsh: hi

在大多数现代的类似 Korn 的 shell 中,它都可以工作。但我不认为这是一个标准,我相信有人喜欢斯蒂芬·查泽拉斯就会知道它有多常见。

答案3

是的,从早期开始就是这样sh

http://www.freebsd.org/cgi/man.cgi?query=sh&apropos=0&sektion=0&manpath=Unix+Seventh+Edition&arch=default&format=html

The environment for any simple-command may be
augmented by prefixing it with  one  or more
assignments to parameters.  Thus these two lines
are equivalent

      TERM=450 cmd args
      (export TERM; TERM=450; cmd args)

答案4

给定示例中的命令,echo将会运行,但发生的情况$APPLE有点复杂。

正如 @Patrick 的答案所示,确实如此,如果 shell 调用一个进程,则在调用之前在命令行上声明的所有变量都被指定导出到其环境中。此外,这些变量也被指定为随着调用的进程而过期 - 所以......

unset var; var=val cmd; echo ${var-unset.}

...应该打印unset.

但是,整个概念变得有点复杂,正如您自己的示例所示,就在这一点cmd不是一个被调用的进程,但可以是 shell 内置进程、shell 函数或特别的shell 内置实用程序。在这三种情况中的每一种情况下,shell 很可能只是在内存中运行一些自己的例程,并且根本不调用任何内容。

例如,echo几乎肯定shell 内置实用程序 - 正如我所知道的大多数 shell 一样提供它 - 但它是不是POSIX 指定的特别的内置。这样,它基本上是一个必须模拟外部可执行文件的 shell 函数。这可能说得更清楚一点这里:

术语“内置”意味着 shell 可以直接执行实用程序而无需搜索它。实现可以选择将任何实用程序设为内置;但是,此处描述的特殊内置实用程序与常规内置实用程序不同......

使用特殊内置实用程序指定的变量分配在内置完成后仍然有效;常规内置实用程序或其他实用程序则并非如此。

本节中的特殊内置实用程序不需要以可通过 POSIX.1-2008 系统接口卷中定义的 exec 系列函数访问的方式提供。

echo因此,在的命令行上声明的变量会随着 一起消失echo,但在set的命令行上声明的变量仍然存在 -(尽管bash默认情况下违反了此规则)。当cmd是 a 时,同样成立功能:

当一个函数被执行时,它应该有语法错误和为特殊内置实用程序描述的变量赋值属性在特殊内置实用程序开头的枚举列表中。

相关内容