如何扩展路径中的波形符 (~)

alv*_*ery 3 regex bash shell ls

我有一个 shell 脚本,可以从用户那里获取目录路径,但我需要检查目录是否为空。如果用户输入他的主路径~而不是绝对路径,那么我无法检查它ls

  echo "Specify your project root directory. For example: ~/Base/project1"

  read directory

  if [ ! -z "$directory" ]
  then

    if [ "$(ls -A "$directory")" ]
    then
      echo Directory $directory is not empty
    else
      echo The directory $directory is empty '(or non-existent)'
    fi
    directory="$directory"

  else

    echo "No root directory specified. Exiting.."
    exit;

  fi
Run Code Online (Sandbox Code Playgroud)

我收到错误: ls 无法使用 ~ 读取路径,如何在检查目录为空之前扩展它?

Wil*_*den 5

eval只要目录规范有效,Ruslan 的使用建议就保证有效。但是,如果用户输入恶意内容(或者只是意外输入会导致副作用的内容),它确实会使您面临任意代码执行的风险。

如果您的 shell 有printf支持的%q(Bash 支持),您可以使用它来转义路径中的所有危险字符,然后让 Bash 扩展它eval

if [ "${directory:0:1}" == \~ ]; then
    eval directory="$(printf '~%q' "${directory#\~}")"
fi
Run Code Online (Sandbox Code Playgroud)

否则,您可以手动扩展波形符。赛勒斯的答案对于像这样的路径~/some/path(未指定用户)效果很好,但对于像~somebody/some/path.

为了处理这种情况,我们可以使用查找用户的主目录getent并手动扩展路径:

prefix=${directory%%/*}
if [ "$prefix" == \~ ]; then
    # Implicitly use current user.
    user=$USER
else
    # Parse user from tilde prefix.
    user=${prefix#\~}
fi

# Get the home directory of the user.  Only expand if the expanded directory exists.
homedir=$(getent passwd -- "$user" | cut -d: -f6)
if [ -d "$homedir" ]; then
    # Replace the tilde prefix with the absolute path to the home directory.
    directory=$homedir${directory#$prefix}
fi
Run Code Online (Sandbox Code Playgroud)

这模仿了 shell 的行为,无效的主目录规范(例如,~baduser/)将保持原样。