bash 脚本不能很好地与其他命令行实用程序一起使用

bash script not playing nicely with other command line utilities

几周前我创建了以下 bash 函数并将其添加到我的 bash 配置脚本中:

cd() {
  if [ "$PS1" ]
    then
    if [ "" ]
      then pushd "" >/dev/null && ls $LS_OPTIONS
      else pushd >/dev/null && ls $LS_OPTIONS
    fi
  else
    if [ "" ]
      then pushd "" >/dev/null
      else pushd >/dev/null
    fi
  fi
}

直到最近我才遇到问题,当时它阻止了一些其他命令的正常运行,我不得不注释掉该功能。例如,在尝试克隆 heroku 应用程序时,我得到:

environment: line 8: pushd: -P: invalid number
pushd: usage: pushd [-n] [+N | -N | dir]
environment: line 8: pushd: -P: invalid number
pushd: usage: pushd [-n] [+N | -N | dir]
environment: line 10: pushd: no other directory

并且当尝试使用 rbenv 安装 ruby 时,它会抛出一个错误,类似于 "pwd did not return a directory",直到我注释掉这个函数。

我只知道 bash 是危险的,我不确定函数中的什么可能导致头痛。

覆盖 cd 意味着任何需要 "regular" cd 的代码都将使用您的函数。第一个问题是您的函数假定第一个参数是目录,但您的错误表明某些用途正在传递不同的选项(如 -P)作为第一个参数。您可以很容易地解决这个问题,只需传递 all 个参数,而不仅仅是第一个参数。这也同时处理零参数情况。

cd() {
  if [ "$PS1" ]
    then
    pushd "$@" >/dev/null && ls $LS_OPTIONS
  else
    pushd "$@" >/dev/null
  fi
}

但是,错误信息中的-P表示下一个问题。 cdpushd 不采用相同的选项,因此假设调用 cd 的代码可以传递 pushd 无法识别的选项。

$ help cd | head -1
cd: cd [-L|[-P [-e]] [-@]] [dir]
$ help pushd | head -1
pushd: pushd [-n] [+N | -N | dir]
但是,

pushd 可以添加到目录堆栈 而无需 更改目录,因此您可以在函数中使用这两个命令。 builtin 命令可让您调用原始 cd 而不会陷入无限递归。

cd () {
  # Identify the directory argument, if any
  for arg; do
    case $arg in
      -L | -P | -e | -@) ;;
      *) dir="$arg"; break ;;
    esac
  done

  # Process the real cd command
  builtin cd "$@" && 
    if [ "$dir" ]; then
      # If there was a directory argument, push it on the stack
      pushd -n "$dir"
    fi &&
    if [ "$PS1 " ]; then
      # If it's an interactive shell, run ls
      ls $LS_OPTIONS
    fi
}

不过,承认您确实想要覆盖 pushd 并训练自己使用它而不是 cd 可能更简单。

pushd () {
  builtin pushd "$@" &&
    if [ "$PS1" ]; then
      ls $LS_OPTIONS
    fi
}