【问题标题】:What is the difference between alias and export (and a function!)[BASH]?别名和导出(以及函数!)[BASH] 之间有什么区别?
【发布时间】:2014-06-04 01:50:16
【问题描述】:

我很惊讶以前没有被问过,但是……

有什么区别

别名 ⇢ alias EXPORT='alias'

功能 ⇢ function exporter() { echo $EXPORT }

和

导出 ⇢ export ALIAS='export'

就此而言......

alias export=$(function) (j/k)

在bash(zsh,等人)

具体来说,我最感兴趣的是了解两者之间的词汇/实际区别

alias this=that

和

export that=this

我有两种形式...到处都是 - 我宁愿停止任意选择一种,而不是另一种。 ????

我确信在某处对“unix shell 的作用域和用例”有很好的参考……但我想我会以 righteous-canonicalicism。

【问题讨论】:

  • 另外,恐怕你的问题的表述方式似乎过于宽泛。
  • 不幸的是,您的示例无助于理解您的疑问或您想要实现的目标。
  • 作为一般规则,总是更喜欢函数而不是别名(除非您知道别名更可取,这种情况很少发生)。
  • 您的个人资料表明您熟悉 C。您可以认为别名类似于 #defines,而函数当然类似于函数。

标签: bash shell command zsh apropos


【解决方案1】:

您问的是两种截然不同的事物:别名和函数定义了类似于命令的事物; export 标记要导出到子进程的变量。让我先介绍一下类似命令的东西:

别名 (alias ll='ls -l') 定义命令的简写。它们旨在用于交互式使用(它们实际上在 shell 脚本中默认禁用),并且简单但不灵活。例如,您在别名之后指定的任何参数都会简单地附加到命令的末尾;如果你想要alias findservice='grep "$1" /etc/services' 之类的东西,你不能这样做,因为$1 在这里没有做任何有用的事情。

函数就像一个更灵活、更强大的别名版本。函数可以接受和处理参数,包含循环、条件、here-documents 等……基本上,你可以用 shell 脚本做的任何事情都可以在函数中完成。请注意,定义函数的标准方法实际上并不使用关键字function,只是在名称后面加上括号。例如:findservice() { grep "$1" /etc/services; }

好的,现在开始讨论 shell 变量。在我到达export 之前,我需要谈谈未导出的变量。基本上,您可以将变量定义为具有某些(文本)值,然后如果您通过$variablename 引用该变量,它将被替换到命令中。这在两个方面与别名或函数不同:别名或函数只能作为命令中的第一个字出现(例如,ll filename 将使用别名 ll,但 echo ll 不会),并且变量必须是用$ 显式调用(@​​987654333@ 将使用变量 foo,但echo foo 不会)。更根本的是,别名和函数旨在包含可执行代码(命令、shell 语法等),而变量旨在存储不可执行的数据。

(顺便说一句,您几乎应该总是将变量引用放在双引号内——也就是说,使用echo "$foo" 而不是仅仅使用echo $foo。没有双引号,变量的内容会以一种有点奇怪的方式被解析,这往往会导致导致错误。)

还有一些“特殊”的shell 变量,它们由shell 自动设置(例如$HOME),或者影响shell 的行为方式(例如$PATH 控制它在哪里查找可执行命令),或者两者兼而有之。

exported 变量既可以在当前 shell 中使用,也可以传递给任何子进程(子 shell、其他命令等)。例如,如果我执行LC_ALL=en_US.UTF-8,这会告诉我当前的 shell 使用“en_US.UTF-8”语言环境设置。另一方面,如果我做了export LC_ALL=en_US.UTF-8,它会告诉当前shell以及它执行的所有子进程和命令使用该语言环境设置。

请注意,shell 变量可以单独标记为导出,而不是定义它,并且一旦导出,它就会保持导出状态。例如,$PATH(据我所知)总是被导出,所以PATH=/foo:/bar 与export PATH=/foo:/bar 具有相同的效果(尽管后者可能是首选,以防万一 $PATH 不知何故'尚未导出)。

也可以将变量导出到特定命令而不在当前shell中定义它,通过使用赋值作为命令的前缀。例如LC_ALL=en_US.UTF-8 sort filename 将告诉sort 命令使用“en_US.UTF-8”语言环境设置,但不会将其应用于当前shell(或任何其他命令)。

【讨论】:

  • 很好的答案.. 跟进.. 声明的alias 和函数的范围是什么?它们也可用于子外壳/子进程等吗?如果不是,导出是一种可以强制这种继承的机制吗?
  • 在您的回答中,似乎只有变量可以标记为已导出。函数也可以导出:fun() { echo hello; }; bash -c 'fun' 会引发bash: fun: command not found 错误,但在export -f fun 之后,bash -c 'fun' 会打招呼:)。
  • bash 允许导出函数(使用export -f),但这是一个仅限 bash 的功能——我不知道任何其他可以导出函数或理解函数的 shell通过 bash 导出给他们。所以,这种能力是存在的,但它是非标准的,有点奇怪。另外,据我所知,没有任何 shell 支持导出别名。
  • 好答案。让别名在 shell 脚本中工作的一个小解决方法是使用 source 作为 shell 脚本。例如,我有一些我喜欢以交互方式使用的别名。我还有一个脚本,它将命令应用于一堆本地 GIT 存储库。我想将别名与在所有这些地方重新运行它们的脚本一起使用。为此,我将apply 别名定义为source do-command-everywhere.sh。工作正常(只要你不使用exit!),因为脚本只是在当前进程中运行。
  • source 仅适用于交互式 shell。如果您有一个带有函数和别名的库脚本,您可以获取它并且别名将起作用,但如果您在另一个脚本中执行相同的源,则默认情况下它不会起作用。你需要“shopt -s expand_aliases”让它工作。
【解决方案2】:

TL;DR:

  1. 您问题中实体的 shell 评估顺序(按 POSIX)是:
    aliases --> variables --> command substitutions --> special built-ins --> functions --> regular built-ins
  2. 别名不会在子 shell 之间保持不变,但可以使用 export 命令使变量(以及 Bash 中的函数)保持不变。
  3. 可以通过编写与常规内置函数同名的函数来覆盖常规内置函数(因为函数在常规内置函数之前扩展)。 (注意:如果您尝试向常规内置函数添加功能,请在函数定义中使用 command 调用内置函数,以免意外创建递归函数。)
  4. 可以使用(特殊的内置)readonly 命令将变量设为只读,但别名不能。

用例:

  1. 如果您需要跨子 shell 使用变量,请导出变量。
  2. 如果您不希望在父 shell 的生命周期内更改变量 readonly(一旦执行,就无法使用 unset 撤消;您必须重新启动父 shell)。
  3. 如果您想覆盖或添加常规内置函数的功能,请使用函数。

注意: 如果您想确定您使用的是特殊或常规内置函数,而不是其他人的函数,请使用 builtin the_builtin, 或者如果shell不支持builtin命令,使用POSIX命令command -p the_builtin,其中-p开关告诉命令默认使用 shell 附带的 $PATH(以防用户覆​​盖了路径)。

注意: 可以使变量像别名一样在子shell 中持续存在并且不能更改。例如,

#! /bin/sh

my_cmd='ls -al'
export my_cmd
readonly my_cmd

会表现得像

#! /bin/sh

alias my_cmd='ls -al'

只要

  1. my_cmd 使用时不带双引号(即 ${my_cmd},NOT "${my_cmd}")因此不被处理作为单个字符串,并且
  2. IFS 是标准 space-tab-newline 并没有切换到别的东西,所以 my_cmd 的元素是通配的,每个部分用空格隔开评估为单个标记(否则它将被评估为单个字符串)。

每个 shell(例如 bash、zsh、ksh、yash 等)都有些不同,因此请务必查看它的参考手册(它们都以独特的方式实现 POSIX ,或者有时根本没有)。

【讨论】:

    猜你喜欢
    • 2014-07-10
    • 2010-12-19
    • 2011-04-16
    • 1970-01-01
    • 2021-12-17
    • 2020-11-27
    • 2011-09-01
    • 1970-01-01
    • 2011-11-12
    相关资源
    最近更新 更多