mad*_*mha 120 bash scripting tilde tilde-expansion
我的bash脚本中有一个变量,其值如下所示:
~/a/b/c
Run Code Online (Sandbox Code Playgroud)
请注意,它是未扩展的波形符号.当我对这个变量执行ls -lt(称之为$ VAR)时,我没有这样的目录.我想让bash解释/扩展这个变量而不执行它.换句话说,我希望bash运行eval但不运行evaluate命令.在bash中这可能吗?
我是如何在不扩展的情况下将其传递到我的脚本中的?我用双引号传递了围绕它的论点.
试试这个命令看看我的意思:
ls -lt "~"
Run Code Online (Sandbox Code Playgroud)
这正是我所处的情况.我想要扩展代字号.换句话说,我应该用什么来代替魔法来使这两个命令相同:
ls -lt ~/abc/def/ghi
Run Code Online (Sandbox Code Playgroud)
和
ls -lt $(magic "~/abc/def/ghi")
Run Code Online (Sandbox Code Playgroud)
请注意〜/ abc/def/ghi可能存在也可能不存在.
Håk*_*and 99
如果变量var是由用户输入的,eval应该不使用利用扩展波形符
eval var=$var # Do not use this!
Run Code Online (Sandbox Code Playgroud)
原因是:用户可能会偶然(或按目的)键入类型,例如var="$(rm -rf $HOME/)"可能带来灾难性后果.
更好(更安全)的方法是使用Bash参数扩展:
var="${var/#\~/$HOME}"
Run Code Online (Sandbox Code Playgroud)
wkl*_*wkl 87
由于StackOverflow的性质,我不能仅仅接受这个答案,但是在我发布这篇文章的5年间,我得到的答案远比我公认的基本和非常糟糕的答案要好得多(我很年轻,不要杀人)我).
该主题中的其他解决方案是更安全,更好的解决方案.我最好选择以下两种方法之一:
出于历史目的的原始答案(但请不要使用此)
如果我没有弄错的话,"~"不会以这种方式扩展bash脚本,因为它被视为文字字符串"~".您可以通过eval这样强制扩展.
#!/bin/bash
homedir=~
eval homedir=$homedir
echo $homedir # prints home path
Run Code Online (Sandbox Code Playgroud)
或者,只要${HOME}您想要用户的主目录即可使用.
Cha*_*ffy 20
将自己从先前的答案中抹去,以便在没有与eval以下相关的安全风险的情况下做到这一点:
expandPath() {
local path
local -a pathElements resultPathElements
IFS=':' read -r -a pathElements <<<"$1"
: "${pathElements[@]}"
for path in "${pathElements[@]}"; do
: "$path"
case $path in
"~+"/*)
path=$PWD/${path#"~+/"}
;;
"~-"/*)
path=$OLDPWD/${path#"~-/"}
;;
"~"/*)
path=$HOME/${path#"~/"}
;;
"~"*)
username=${path%%/*}
username=${username#"~"}
IFS=: read -r _ _ _ _ _ homedir _ < <(getent passwd "$username")
if [[ $path = */* ]]; then
path=${homedir}/${path#*/}
else
path=$homedir
fi
;;
esac
resultPathElements+=( "$path" )
done
local result
printf -v result '%s:' "${resultPathElements[@]}"
printf '%s\n' "${result%:}"
}
Run Code Online (Sandbox Code Playgroud)
......用作......
path=$(expandPath '~/hello')
Run Code Online (Sandbox Code Playgroud)
或者,一种更简单的方法eval:
expandPath() {
case $1 in
~[+-]*)
local content content_q
printf -v content_q '%q' "${1:2}"
eval "content=${1:0:2}${content_q}"
printf '%s\n' "$content"
;;
~*)
local content content_q
printf -v content_q '%q' "${1:1}"
eval "content=~${content_q}"
printf '%s\n' "$content"
;;
*)
printf '%s\n' "$1"
;;
esac
}
Run Code Online (Sandbox Code Playgroud)
gli*_*ond 10
这是一个荒谬的解决方案:
$ echo "echo $var" | bash
Run Code Online (Sandbox Code Playgroud)
该命令的作用的解释:
bash;"echo $var"并替换$var为变量的值(因此替换后字符串将包含波形符);echo和管道输出来完成此操作|。基本上,我们正在运行的当前 bash 实例取代了我们作为另一个 bash 实例的用户的位置,并为我们输入命令"echo ~..."。
使用eval的一种安全方法是"$(printf "~/%q" "$dangerous_path")".请注意,这是特定于bash的.
#!/bin/bash
relativepath=a/b/c
eval homedir="$(printf "~/%q" "$relativepath")"
echo $homedir # prints home path
Run Code Online (Sandbox Code Playgroud)
有关详情,请参阅此问题
另外,请注意在zsh下这将是一样简单 echo ${~dangerous_path}
这个怎么样:
path=`realpath "$1"`
Run Code Online (Sandbox Code Playgroud)
要么:
path=`readlink -f "$1"`
Run Code Online (Sandbox Code Playgroud)
在birryree和halloleo的答案上扩展(没有双关语):一般方法是使用eval,但它带有一些重要的警告,即>变量中的空格和输出重定向().以下似乎对我有用:
mypath="$1"
if [ -e "`eval echo ${mypath//>}`" ]; then
echo "FOUND $mypath"
else
echo "$mypath NOT FOUND"
fi
Run Code Online (Sandbox Code Playgroud)
尝试使用以下每个参数:
'~'
'~/existing_file'
'~/existing file with spaces'
'~/nonexistant_file'
'~/nonexistant file with spaces'
'~/string containing > redirection'
'~/string containing > redirection > again and >> again'
Run Code Online (Sandbox Code Playgroud)
${mypath//>}带出来>的字符可能在揍一个文件eval. eval echo ...是什么是实际的波浪线扩展-e参数周围的双引号用于支持带空格的文件名.也许有一个更优雅的解决方案,但这是我能够想到的.