如何在路径中扩展波浪号(〜)

时间:2016-10-19 10:12:05

标签: 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

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

2 个答案:

答案 0 :(得分:3)

只要目录规范有效,Ruslan建议使用eval就可以正常工作。但是,如果用户输入恶意内容(或者只是偶然输入导致副作用的内容),它确实会使您暴露于任意代码执行。

如果你的shell有printf支持%q(Bash会这样做),你可以使用它来转义路径中的所有危险字符,然后让Bash使用{{1}扩展它}:

eval

否则,您可以手动展开代字号。 Cyrus的答案适用于if [ "${directory:0:1}" == \~ ]; then eval directory="$(printf '~%q' "${directory#\~}")" fi (未指定用户)等路径,但对~/some/path之类的路径失败。

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

~somebody/some/path

这模仿了shell的行为,因为无效的主目录规范(例如,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 )将保持不变。

答案 1 :(得分:2)

原始答案

试试这个:

eval directory="$directory"

由于没有什么能比shell本身更好地解释特殊的shell字符,所以最好让shell为我们评估表达式。 eval只是评估shell表达式的命令。

备选方案#1:C

中的程序

然而,eval是不安全的,因为它已被多次提及, - 它可能会执行恶意代码或导致不必要的影响。然后,对于POSIX环境,您可以用C:

编写一个简单的程序

<强> tildeexp.c

#include <stdio.h>
#include <stdlib.h>
#include <wordexp.h>

int
main(int argc, char **argv)
{
  wordexp_t p;
  int rc;

  rc = wordexp(argv[1], &p, 0);
  if (rc) {
    fprintf(stderr, "Failed to expand %s: %d\n",
        argv[1], rc);
  } else {
    printf("%s\n", p.we_wordc ? p.we_wordv[0] : "");
  }
  wordfree(&p);

  return (rc ? 1 : 0);
}

编译

gcc -Wall -g -O2 -o tildeexp tildeexp.c

用法

directory=$(/path/to/tildeexp "$directory")
if [ $? -eq 0 ]; then
  # success
else
  # failed to expand
fi

备选方案#2:Perl&#39; glob

directory="${directory//$"'"/$"\\'"}"
directory=$(perl -e "print glob('$directory')")