내 bash 스크립트에 값이 다음과 같은 변수가 있습니다.
~/a/b/c
확장되지 않은 물결표입니다. 이 변수에 대해 ls -lt를 수행하면 ($ VAR이라고 함) 그러한 디렉토리가 없습니다. bash 가이 변수를 실행하지 않고 해석 / 확장하도록하고 싶습니다. 즉, bash가 eval을 실행하고 평가 된 명령은 실행하지 않기를 원합니다. bash에서 가능합니까?
확장하지 않고 스크립트에 어떻게 전달 했습니까? 나는 큰 따옴표로 둘러싼 논쟁을 통과시켰다.
이 명령을 사용하여 무슨 뜻인지 확인하십시오.
ls -lt "~"
이것이 바로 내가 처한 상황입니다. 물결표가 확장되기를 원합니다. 다시 말해,이 두 명령을 동일하게하기 위해 마법을 대체해야하는 것은 무엇입니까?
ls -lt ~/abc/def/ghi
과
ls -lt $(magic "~/abc/def/ghi")
~ / abc / def / ghi가 존재할 수도 있고 존재하지 않을 수도 있습니다.
답변
StackOverflow의 특성으로 인해이 답변을 받아 들일 수는 없지만이 게시물을 게시 한 후 5 년 동안 저의 초보적이고 꽤 나쁜 답변보다 훨씬 더 나은 답변이있었습니다 (어려서 죽이지 마십시오) 나를).
이 스레드의 다른 솔루션은 더 안전하고 더 나은 솔루션입니다. 바람직하게는 다음 두 가지 중 하나를 선택합니다.
역사적인 목적을위한 독창적 인 답변 (그러나 이것을 사용하지 마십시오)
내가 실수 "~"
하지 않으면 리터럴 문자열로 취급되기 때문에 bash 스크립트로 확장되지 않습니다 "~"
. eval
이런 식으로 확장을 강제 할 수 있습니다 .
#!/bin/bash
homedir=~
eval homedir=$homedir
echo $homedir # prints home path
또는 ${HOME}
사용자의 홈 디렉토리를 원할 경우 사용 하십시오.
답변
var
사용자가 변수 를 입력 한 경우 다음을 사용하여 물결표를 확장하는 데 사용 eval
해서는 안됩니다 .
eval var=$var # Do not use this!
그 이유는 다음과 같습니다. 사용자는 우연히 (또는 목적에 따라) 유형으로 예를 들어 var="$(rm -rf $HOME/)"
재앙이 발생할 수 있습니다.
더 좋고 안전한 방법은 Bash 매개 변수 확장을 사용하는 것입니다.
var="${var/#\~/$HOME}"
답변
다음 과 관련된 보안 위험없이이를 강력하게 수행 하기 위해 사전 답변 에서 나 자신을 표명합니다 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%:}"
}
…로 사용 …
path=$(expandPath '~/hello')
또는 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
}
답변
eval을 사용하는 안전한 방법은 "$(printf "~/%q" "$dangerous_path")"
입니다. 배쉬 전용입니다.
#!/bin/bash
relativepath=a/b/c
eval homedir="$(printf "~/%q" "$relativepath")"
echo $homedir # prints home path
자세한 내용은 이 질문 을 참조하십시오
또한 zsh에서 이것은 다음과 같이 간단합니다. echo ${~dangerous_path}
답변
이건 어때요:
path=`realpath "$1"`
또는:
path=`readlink -f "$1"`
답변
Birryrees와 Halloleo의 답변에 대한 확장 (장어 의도 없음) : 일반적인 접근 방식은을 사용하는 eval
것이지만 >
변수에 공백과 출력 리디렉션 ( ) 과 같은 몇 가지주의 사항 이 있습니다. 다음은 저에게 효과적입니다.
mypath="$1"
if [ -e "`eval echo ${mypath//>}`" ]; then
echo "FOUND $mypath"
else
echo "$mypath NOT FOUND"
fi
다음 각 인수로 시도하십시오.
'~'
'~/existing_file'
'~/existing file with spaces'
'~/nonexistant_file'
'~/nonexistant file with spaces'
'~/string containing > redirection'
'~/string containing > redirection > again and >> again'
설명
- 은
${mypath//>}
떼어 내고>
동안 파일을 소지품 수있는 자eval
. - 는
eval echo ...
실제 틸드 확장을하는 일이다 -e
인수 주위의 큰 따옴표 는 공백이있는 파일 이름을 지원하기위한 것입니다.
아마도 더 우아한 해결책이 있지만 이것이 내가 생각해 낸 것입니다.
답변
나는 이것이 당신이 찾고있는 것이라고 믿습니다.
magic() { # returns unexpanded tilde express on invalid user
local _safe_path; printf -v _safe_path "%q" "$1"
eval "ln -sf ${_safe_path#\\} /tmp/realpath.$$"
readlink /tmp/realpath.$$
rm -f /tmp/realpath.$$
}
사용법 예 :
$ magic ~nobody/would/look/here
/var/empty/would/look/here
$ magic ~invalid/this/will/not/expand
~invalid/this/will/not/expand
