Расширение Тильды происходит очень рано в процессе синтаксического анализа, и нет никаких способов добиться того, чего вы хотите без нескольких оценок. Следовательно, eval
- решение. Самый безопасный способ добиться того, что вы хотите:
eval "$(printf "home=~%q" "$user")"
Благодаря модификатором %q
, расширение $user
будет полностью цитировал, так что нет никакой опасности здесь (не изменить строку, хотя, вы, конечно, ввести некоторые дыры в безопасности).
Вы не должны использовать это самостоятельно: после этой линии, вы должны убедиться, что вы получаете правильный каталог, например,
if [[ ! -d $home ]]; then
echo >&2 "Couldn't find home dir for user $user"
exit 1
fi
Также рассмотрим случай, когда user
пусто: в этом случае, home
будет домашним каталогом пользователя, запускающего скрипт. Хочешь ли ты этого поведения или нет, зависит от тебя.
Существует еще один момент для рассмотрения: когда user
содержит косые черты: хотите ли вы эту функцию или нет, зависит от вас.
Теперь, в зависимости от того, каких функций вы хотите иметь, это могло бы быть лучше, чтобы подтвердить расширение $user
против какой-то определенной схемы один раз для всех, например,
if [[ $user != [a-z]*([-a-z0-9_]) ]]; then
echo >&2 'Provided user doesn't match valid pattern'
exit 1
fi
И получается, что с этой проверкой, ваше решение безопасно.
Примеры:
Случай, когда все работает хорошо:
$ user=gniourf
$ eval "$(printf "home=~%q" "$user")"
$ declare -p home
declare -- home="/home/gniourf"
Случай, который может быть опасным с кодом (с кодом, ls
будет выполнен, но не здесь) :
$ user='; ls >&2'
$ eval "$(printf "home=~%q" "$user")"
$ declare -p home
declare -- home="~; ls >&2"
что-то вроде '$ (cd ~; pwd)' может быть? – n0rd
@ n0rd - Я думаю, что OP означает, что им нужно получить домашнюю папку данного имени пользователя, имя пользователя, указанное из ненадежного источника. –
'eval' опасен на * неутвержденный * вход; вы можете убедиться, что '$ user' содержит только допустимое имя пользователя с чем-то вроде [[$ user = ~ [a-zA-Z] [a-zA-Z0-9_]]] && home = $ (eval echo ~ $ пользователю) '. (Я точно не помню, что представляет собой действительное имя пользователя, но это что-то вроде действительного идентификатора.) – chepner