如何打开和关闭通配符?

Joh*_*ofy 10 bash alias shell-script wildcards bashrc

在我~./bashrc的别名中,我已经不再像这样使用通配符了。

alias x='set -f;. any.sh'
Run Code Online (Sandbox Code Playgroud)

但是哪个命令可以再次启用通配符,还是应该在 中设置此选项any.sh

欢迎任何回应。

Sté*_*las 12

如果你想水珠是仅在外壳解释代码中禁用any.sh,有bash4.4+ash基于炮弹,你可以这样做:

x() {
  local -
  set -o noglob
  . any.sh
}
Run Code Online (Sandbox Code Playgroud)

或在zsh

x() {
  set -o localoptions -o noglob
  . any.sh
}
Run Code Online (Sandbox Code Playgroud)

那是使用函数而不是别名(您不想为多个命令使用别名,因为这在您执行cmd | xcmd && x例如执行时不会执行您想要的操作),确保更改选项(将$-变量作为一种方式)查看它)是函数本地的,禁用 glob 并获取文件。

使用旧版本的bash,您可以执行以下操作:

x() {
  local ret restore
  [[ $- = *f* ]] || restore='set +o noglob'
  set -o noglob
  . any.sh
  ret=$?
  eval "$restore"
  return "$ret"
}
Run Code Online (Sandbox Code Playgroud)

或者可能是一个更通用的辅助函数,例如:

withopt() {
  local ret option
  local -a restore
  option=$1; shift
  [[ -o $option ]] || restore=(set +o "$option")

  set -o "$option"
  "$@"
  ret=$?
  "${restore[@]}"
  return "$ret"
}
Run Code Online (Sandbox Code Playgroud)

然后,如果您愿意,可以使用别名:

alias x='withopt noglob . any.sh'
Run Code Online (Sandbox Code Playgroud)

请注意,*如果您这样做,它不会阻止被扩展:

x *
Run Code Online (Sandbox Code Playgroud)

由于该noglob选项在评估该命令后很长时间才被启用。为此,请参阅我的其他答案另一个问题的答案)。

  • @JohnGoofy,如果您的脚本需要禁用 glob,为什么不将 `set -f` 添加到您的脚本中?我不确定我是否理解您的用例。 (2认同)

Sté*_*las 5

这是在问题澄清之前发布的,现在解决了不同的需求。我仍然把它留在这里,因为这对其他人可能有用。

我想你希望能够做到:

x *.txt
Run Code Online (Sandbox Code Playgroud)

以及*.txt要传递的未展开的any.sh和随后重新启用的 glob。

你不能用 来做到这一点bashzsh在你可以做的地方使用:

alias x='noglob any.sh`
Run Code Online (Sandbox Code Playgroud)

其中noglob仅禁用该命令的别名。

$ echo /etc/p*d
/etc/pam.d /etc/passwd /etc/profile.d
$ noglob echo /etc/p*d
/etc/p*d
Run Code Online (Sandbox Code Playgroud)

请注意,它仅影响该命令参数中的 glob 扩展echo*仍会在noglob echo $(echo *)ornoglob eval 'echo *'或 的位置noglob . some-script进行扩展。some-scriptecho *

实际上,可能有一种方法bash

oneshot_noglob() {
  case $- in
    (*f*) ;; # globs already disabled
    (*) set -f; shot=0; debug_trap=$(trap -p DEBUG)
        trap '
          if ((++shot == 2)); then
            set +f
            trap - DEBUG
            '"$debug_trap"'
          fi' DEBUG;;
  esac
}

alias x='oneshot_noglob; any.sh'
Run Code Online (Sandbox Code Playgroud)

它使用 DEBUG 陷阱set +fset -f.

现在,对于包含多个命令的所有别名,有一些注意事项。

echo foo | x
Run Code Online (Sandbox Code Playgroud)

变成:

echo foo | oneshort_noglob; any.sh
Run Code Online (Sandbox Code Playgroud)

因此 的输出echo仅馈送到oneshort_noglob

对于类似的事情也是如此:

cmd && x
Run Code Online (Sandbox Code Playgroud)

any.sh无论cmd成功与否都会执行到哪里。

另请注意,它会影响每个级别的子 shell 中的所有 glob,直到在主 shell 进程中执行第二个命令之前。

例如,在 中x $(echo *; echo *) *,这些都*不会被扩展,因为除非设置该选项,否则 DEBUG 陷阱不会被继承extdebug