别名免除重复敲击
别名在 Bash 读取命令时,把命令位置的一个词替换成一段 Shell 文本。alias ll='ls -l' 这种个人快捷方式很方便,但别名并不是一个可执行文件,也没有独立的位置参数作用域。非交互 Bash 默认关闭别名展开,脚本却可以明确启用它;“默认不展开”与“脚本中绝对不能使用”是两回事。理解这个区别,才能解释为什么终端里好用的简称到了自动化环境就找不到。 替换发生在读取输入时 命令位置上没有被引用的词,才可能被当成别名展开。定义 ll 后,ll 'two words' 仍会把带空格的文本作为一个参数传给命令,不能笼统地说别名必然破坏参数引用。真正的限制是:别名没有属于自己的 $1,也不能像函数那样拥有并重新排列一组独立的参数。调用者后面追加的参数,只是继续参与替换后的命令解析。 替换文本甚至可以包含管道或多条命令,因此别名在语法上并不局限于单一程序。代价是读者更难直接看出简称背后的行为。Bash 会继续检查替换文本的第一个词,但不会再次展开当前正在展开的同名别名,所以 alias ls='ls -F' 不会无限递归。还有一个容易忽略的规则:别名值末尾如果留有空白,紧随其后的命令词也会接受别名检查,不应把尾部空格当成无意义的排版。 定义本身的引号还决定另一层求值时机。单引号让美元符号保留到替换文本以后被解释;双引号却可能在定义别名时就展开变量。原本想跟随目录变量变化的快捷方式,于是可能固定住旧值。遇到这种差异时,应检查实际保存的别名定义,而不只是回看自己最初输入的那一行。 作用域与生效时机分开看 别名属于当前 Shell,不是可以导出给新 Bash 进程的环境变量。圆括号创建的子 Shell 会继承当前 Shell 状态,这与重新启动一个 Bash 程序不同。新进程读取启动文件后出现同名别名,表示配置又执行了一遍,并不证明别名通过环境自动传递。因此排查问题时,应确认命令究竟由当前交互 Shell、圆括号子 Shell,还是另一个程序启动。 shopt -s expand_aliases 能在非交互 Bash 中启用展开,但定义仍须在使用它的输入被读取之前生效。Bash 会先读完一整行或完整复合命令,再执行其中的内容。同一行先定义别名、后调用新名字,并不能赶在解析后半行之前建立定义;把定义塞进正在读取的函数体,也存在同样的时机问题。把定义单独放一行,比依赖分号后的即时生效可靠。 ...