我有一个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无法读取路径〜,如何在检查目录为空之前展开它?
答案 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表达式的命令。
然而,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
glob
directory="${directory//$"'"/$"\\'"}"
directory=$(perl -e "print glob('$directory')")