0

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

cd() {
  if [ "$PS1" ]
    then
    if [ "$1" ]
      then pushd "$1" >/dev/null && ls $LS_OPTIONS
      else pushd >/dev/null && ls $LS_OPTIONS
    fi
  else
    if [ "$1" ]
      then pushd "$1" >/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 没有返回目录”,直到我注释掉这个函数。

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

4

1 回答 1

3

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

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

但是,-P错误消息中的 表示下一个问题。cd并且pushd不要采用相同的选项,因此假设它正在调用的代码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
}
于 2020-06-07T13:09:18.283 回答