如何在路径中扩展波浪号 (~)
How to expand tilde (~) in path
我有一个 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 无法使用 ~ 读取路径,如何在检查目录为空之前展开它?
原回答
试试这个:
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 的 glob
directory="${directory//$"'"/$"\'"}"
directory=$(perl -e "print glob('$directory')")
Ruslan 关于使用 eval
的建议只要目录规范有效就保证有效。但是,如果用户输入恶意内容(或只是不小心输入会导致副作用的内容),它确实会使您面临任意代码执行。
如果您的 shell 有一个 printf
支持 %q
(Bash 支持),您可以使用它来转义路径中的所有危险字符在让 Bash 用 eval
:
扩展它之前
if [ "${directory:0:1}" == \~ ]; then
eval directory="$(printf '~%q' "${directory#\~}")"
fi
否则,您可以手动扩展波浪号。赛勒斯的答案适用于 ~/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
这模仿了 shell 的行为,无效的主目录规范(例如,~baduser/
)将保持原样。
我有一个 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 无法使用 ~ 读取路径,如何在检查目录为空之前展开它?
原回答
试试这个:
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 的 glob
directory="${directory//$"'"/$"\'"}"
directory=$(perl -e "print glob('$directory')")
Ruslan 关于使用 eval
的建议只要目录规范有效就保证有效。但是,如果用户输入恶意内容(或只是不小心输入会导致副作用的内容),它确实会使您面临任意代码执行。
如果您的 shell 有一个 printf
支持 %q
(Bash 支持),您可以使用它来转义路径中的所有危险字符在让 Bash 用 eval
:
if [ "${directory:0:1}" == \~ ]; then
eval directory="$(printf '~%q' "${directory#\~}")"
fi
否则,您可以手动扩展波浪号。赛勒斯的答案适用于 ~/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
这模仿了 shell 的行为,无效的主目录规范(例如,~baduser/
)将保持原样。