bash에서 특수 변수(예: ~ 타일드)를 수동으로 확장하는 방법
bash 스크립트에 다음과 같은 값을 가진 변수가 있습니다.
~/a/b/c
확장되지 않은 타일입니다.이 변수($VAR이라고 함)에 대해 -lt를 수행하면 해당 디렉터리가 표시되지 않습니다.bash가 이 변수를 실행하지 않고 해석/확장할 수 있도록 합니다.다시 말해, 나는 bash가 eval을 실행하고 평가된 명령을 실행하지 않기를 원합니다.이것이 bash에서 가능합니까?
확장하지 않고 어떻게 스크립트에 전달할 수 있었을까요?저는 그 주장을 이중따옴표로 둘러싸서 통과시켰습니다.
이 명령을 사용하여 의미를 확인합니다.
ls -lt "~"
이것이 바로 제가 처한 상황입니다.저는 타일이 확장되기를 원합니다.즉, 이 두 명령을 동일하게 만들려면 마법을 무엇으로 대체해야 합니까?
ls -lt ~/abc/def/ghi
그리고.
ls -lt $(magic "~/abc/def/ghi")
~/abc/def/ghi는 존재할 수도 있고 존재하지 않을 수도 있습니다.
수가변인 var
한 것입니다.eval
를 사용하여 타일을 확장하는 데 사용해서는 안 됩니다.
eval var=$var # Do not use this!
로 (할 수 입니다.var="$(rm -rf $HOME/)"
비참한 결과를 초래할 수도 있습니다.
더 나은(그리고 더 안전한) 방법은 Bash 매개 변수 확장을 사용하는 것입니다.
var="${var/#\~/$HOME}"
StackOverflow의 특성상 이 답변을 수락하지 않도록 할 수는 없지만, 이 글을 올린 이후 5년 동안 제가 인정하는 초보적이고 꽤 나쁜 답변(저는 젊었습니다, 저를 죽이지 마세요)보다 훨씬 더 나은 답변이 있었습니다.
이 스레드의 다른 솔루션은 더 안전하고 더 나은 솔루션입니다.다음 두 가지 중 하나를 사용하는 것이 좋습니다.
역사적인 목적을 위한 원본 답변(단, 이를 사용하지 마십시오.
틀리지 , 내가틀않면다았지리,면."~"
bash 스크립트는 리터럴 문자열로 처리되므로 이러한 방식으로 확장되지 않습니다."~"
다음을 통해 강제로 확장할 수 있습니다.eval
이것처럼.
#!/bin/bash
homedir=~
eval homedir=$homedir
echo $homedir # prints home path
또는 사용하기만 하면 됩니다.${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
}
이거 어때:
path=`realpath "$1"`
또는:
path=`readlink -f "$1"`
eval을 안전하게 사용하는 방법은 다음과 같습니다."$(printf "~/%q" "$dangerous_path")"
이는 bash별로 다릅니다.
#!/bin/bash
relativepath=a/b/c
eval homedir="$(printf "~/%q" "$relativepath")"
echo $homedir # prints home path
자세한 내용은 이 질문을 참조하십시오.
또한, zsh에서 이것은 다음과 같이 간단할 것입니다.echo ${~dangerous_path}
여기에 터무니없는 해결책이 있습니다.
$ echo "echo $var" | bash
이 명령의 기능에 대한 설명:
- bash의 새합니다. bash,calling 르의해새로의운스부다만기.
bash
; - 현을잡라는 합니다.
"echo $var"
및대품으로 합니다.$var
변수 값(대체 후 문자열에 타일이 포함됨); - 합니다. 서는 2단계에서 생성된 bash 인스턴스를 1단계 bash 인스턴스라고 . 여기서 호출합니다.
echo
그리고 그것의 출력을 파이프로 연결합니다.|
성격.
으로 현재되며 "bash" 합니다."echo ~..."
우리를 위하여
Birryree와 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
인수는 공백이 있는 파일 이름을 지원합니다.
어쩌면 더 우아한 해결책이 있을지도 모르지만, 이것이 제가 생각해 낼 수 있었던 것입니다.
gentent와 함께 사용자의 홈 디렉토리를 얻는 것에 대해 직접 탐구하는 것은 어떻습니까?
$ getent passwd mike | cut -d: -f6
/users/mike
이것이 당신이 찾고 있는 것이라고 믿습니다.
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
다음은 Hókon Hägland의 Bash 답변에 해당하는 POSIX 함수입니다.
expand_tilde() {
tilde_less="${1#\~/}"
[ "$1" != "$tilde_less" ] && tilde_less="$HOME/$tilde_less"
printf '%s' "$tilde_less"
}
2017-12-10 추가: 추가'%s'
@Charles Duffy 댓글따.
제 솔루션은 다음과 같습니다.
#!/bin/bash
expandTilde()
{
local tilde_re='^(~[A-Za-z0-9_.-]*)(.*)'
local path="$*"
local pathSuffix=
if [[ $path =~ $tilde_re ]]
then
# only use eval on the ~username portion !
path=$(eval echo ${BASH_REMATCH[1]})
pathSuffix=${BASH_REMATCH[2]}
fi
echo "${path}${pathSuffix}"
}
result=$(expandTilde "$1")
echo "Result = $result"
가장 간단합니다. '매직'을 '평가 에코'로 대체합니다.
$ eval echo "~"
/whatever/the/f/the/home/directory/is
문제:평가는 사악하기 때문에 다른 변수와 문제가 발생할 것입니다.예를 들어:
$ # home is /Users/Hacker$(s)
$ s="echo SCARY COMMAND"
$ eval echo $(eval echo "~")
/Users/HackerSCARY COMMAND
첫 번째 확장에서는 주입 문제가 발생하지 않습니다.그래서 만약 당신이 단순히 대체한다면,magic
와 함께eval echo
당신은 괜찮을 겁니다.하지만 만약 당신이echo $(eval echo ~)
주사에 취약할 수 있습니다.
마찬가지로, 만약 당신이 한다면,eval echo ~
에 eval echo "~"
두 배로 확장되었기 때문에 즉시 주입이 가능할 것입니다.
누구나 참고할 수 있도록 python의 os.path.expanduser() 동작을 모방하는 함수(평가 사용 없음):
# _expand_homedir_tilde ~/.vim
/root/.vim
# _expand_homedir_tilde ~myuser/.vim
/home/myuser/.vim
# _expand_homedir_tilde ~nonexistent/.vim
~nonexistent/.vim
# _expand_homedir_tilde /full/path
/full/path
그리고 기능:
function _expand_homedir_tilde {
(
set -e
set -u
p="$1"
if [[ "$p" =~ ^~ ]]; then
u=`echo "$p" | sed 's|^~\([a-z0-9_-]*\)/.*|\1|'`
if [ -z "$u" ]; then
u=`whoami`
fi
h=$(set -o pipefail; getent passwd "$u" | cut -d: -f6) || exit 1
p=`echo "$p" | sed "s|^~[a-z0-9_-]*/|${h}/|"`
fi
echo $p
) || echo $1
}
공백이 있는 경로에 대한 Birryree의 답변을 확장하기 위해:사용할 수 없습니다.eval
공간별로 평가를 구분하기 때문에 그대로 명령합니다.한 가지 해결책은 eval 명령에 대한 공백을 임시로 바꾸는 것입니다.
mypath="~/a/b/c/Something With Spaces"
expandedpath=${mypath// /_spc_} # replace spaces
eval expandedpath=${expandedpath} # put spaces back
expandedpath=${expandedpath//_spc_/ }
echo "$expandedpath" # prints e.g. /Users/fred/a/b/c/Something With Spaces"
ls -lt "$expandedpath" # outputs dir content
이 예는 물론 다음과 같은 가정에 의존합니다.mypath
시퀀스 문자시를포않지다습니하함스가 되어 있지 않습니다."_spc_"
.
이것은 파이썬에서 더 쉽게 찾을 수 있습니다.
unix 명령줄에서:
python -c 'import os; import sys; print os.path.expanduser(sys.argv[1])' ~/fred
결과:
/Users/someone/fred
- bash로 합니다.test.sh
:
#!/usr/bin/env bash
thepath=$(python -c 'import os; import sys; print os.path.expanduser(sys.argv[1])' $1)
echo $thepath
중입니다.bash ./test.sh
결과:
/Users/someone/fred
- 유리티로 - 장저로 expanduser
실행 권한이 있는 경로의 어딘가:
#!/usr/bin/env python
import sys
import os
print os.path.expanduser(sys.argv[1])
다음 명령행에서 사용할 수 있습니다.
expanduser ~/fred
또는 스크립트에서:
#!/usr/bin/env bash
thepath=$(expanduser $1)
echo $thepath
그냥 사용하기eval
정확하게: 유효성 검사 포함.
case $1${1%%/*} in
([!~]*|"$1"?*[!-+_.[:alnum:]]*|"") ! :;;
(*/*) set "${1%%/*}" "${1#*/}" ;;
(*) set "$1"
esac&& eval "printf '%s\n' $1${2+/\"\$2\"}"
나는 (다른 것들 중에서) read -e를 사용하여 경로에서 읽은 후 변수 매개변수 대체를 사용하여 이 작업을 수행했습니다.따라서 사용자는 경로를 탭 완료할 수 있으며 ~ 경로를 입력하면 정렬됩니다.
read -rep "Enter a path: " -i "${testpath}" testpath
testpath="${testpath/#~/${HOME}}"
ls -al "${testpath}"
추가적인 이점은 타일이 없으면 변수에 아무 일도 일어나지 않으며 타일이 있지만 첫 번째 위치에 있지 않으면 무시된다는 것입니다.
(저는 루프에서 사용하기 때문에 문제가 있을 때 경로를 수정할 수 있도록 -i를 읽기 위해 포함합니다.)
어떤 이유로 문자열이 이미 인용되었을 때 Perl만 하루를 저장합니다.
#val="${val/#\~/$HOME}" # for some reason does not work !!
val=$(echo $val|perl -ne 's|~|'$HOME'|g;print')
나는 생각합니다.
thepath=( ~/abc/def/ghi )
다른 모든 솔루션보다 쉽습니다.아니면 내가 뭔가를 놓쳤나요?경로가 실제로 존재하지 않더라도 작동합니다.
언급URL : https://stackoverflow.com/questions/3963716/how-to-manually-expand-a-special-variable-ex-tilde-in-bash
'source' 카테고리의 다른 글
VSCode로 Angular를 디버깅하는 방법은 무엇입니까? (0) | 2023.05.24 |
---|---|
ASP.NET MVC에서 현재 사용자를 가져오는 방법 (0) | 2023.05.24 |
UITableView가 데이터 다시 로드를 완료했는지 어떻게 알 수 있습니까? (0) | 2023.05.24 |
Xcode 4 스킴의 이름을 바꿀 수 있는 방법이 있습니까? (0) | 2023.05.24 |
LINQ를 사용하여 개체 목록에서 고유한 속성 목록을 가져오려면 어떻게 해야 합니까? (0) | 2023.05.24 |