Простые значения внутри функций не изменят эти значения вне функции (они передаются по значению), тогда как сложные (будут переданы по ссылке).
function willNotChange(x) {
x = 1;
}
var x = 1000;
willNotChange(x);
document.write('After function call, x = ' + x + '<br>'); //still 1000
function willChange(y) {
y.num = 2;
}
var y = {num: 2000};
willChange(y);
document.write('After function call y.num = ' + y.num + '<br>'); //now 2, not 2000
Просто для продолжения ответа 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_"
.
Безопасный способ использования 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}
${HOME}
наиболее привлекательным. Есть ли причина, чтобы не сделать это основной рекомендацией? В любом случае, спасибо!
– sage
5 September 2013 в 16:21
eval
- ужасное предложение, это действительно плохо, что он получает так много upvotes. Вы столкнетесь со всеми проблемами, когда значение переменной содержит метасимволы оболочки.
– user2719058
31 August 2014 в 20:47
Плагировать себя из предварительного ответа , чтобы сделать это без риска безопасности, связанного с 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 _ _ _ _ _ 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
}
printf %q
для удаления всего, кроме тильды, а then i> использовать eval
без риска.
– Charles Duffy
21 August 2015 в 13:57
Вы можете найти это проще в python.
(1) Из командной строки unix:
python -c 'import os; import sys; print os.path.expanduser(sys.argv[1])' ~/fred
Результаты в:
/Users/someone/fred
(2) В сценарии 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
( 3) В качестве полезности - сохраните это как 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
echo $thepath
глючит; должен быть echo "$thepath"
для исправления менее необычных случаев (имена с табуляторами или пробелами, которые преобразуются в одиночные пробелы, имена с расширением глобусов) или printf '%s\n' "$thepath"
, чтобы исправить необычные (например, файл named -n
или файл с символами обратной косой черты в XSI-совместимой системе). Аналогично, thepath=$(expanduser "$1")
– Charles Duffy
13 December 2015 в 07:12
echo
вести себя в полностью определенной реализации если любой аргумент содержит обратную косую черту; дополнительные расширения XSI для мандата POSIX по умолчанию (нет необходимости -e
или -E
) для таких имен.
– Charles Duffy
13 December 2015 в 07:13
Вот мое решение:
#!/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"
echo
, означает, что expandTilde -n
не будет вести себя так, как ожидалось, а поведение с именами файлов, содержащими обратную косую черту, не определено POSIX. См. pubs.opengroup.org/onlinepubs/009604599/utilities/echo.html
– Charles Duffy
21 August 2015 в 14:14
Вот функция POSIX, эквивалентная Bash Håkon Hægland's answer
expand_tilde() {
tilde_less="${1#\~/}"
[ "$1" != "$tilde_less" ] && tilde_less="$HOME/$tilde_less"
printf '%s' "$tilde_less"
}
2017-12-10 edit: добавьте '%s'
за @CharlesDuffy в комментариях.
printf '%s\n' "$tilde_less"
, возможно? В противном случае это будет неверно, если расширение файла будет содержать обратные косые черты, %s
или другой синтаксис, значимый для printf
. Кроме этого, однако, это отличный ответ - правильный (когда расширения bash / ksh не нужно закрывать), очевидно, безопасно (без смешивания с eval
) и кратким.
– Charles Duffy
8 December 2017 в 22:53
Если переменная var
вводится пользователем, eval
не следует использовать для расширения тильды с использованием
eval var=$var # Do not use this!
. Причина в том, что пользователь может случайно (или по назначению ) типа var="$(rm -rf $HOME/)"
с возможными катастрофическими последствиями.
Лучшим (и безопасным) способом является использование расширения параметра Bash:
var="${var/#\~/$HOME}"
$var
.
– Håkon Hægland
2 June 2015 в 17:27
\~
, т. Е. Экранирование ~
? (2) В вашем ответе предполагается, что ~
является первым символом в $var
. Как мы можем игнорировать ведущие пробелы в $var
?
– Tim
5 May 2018 в 01:16
Simplest: замените «magic» на «eval echo».
$ eval echo "~"
/whatever/the/f/the/home/directory/is
Проблема: вы столкнетесь с проблемами с другими переменными, потому что eval - это зло. Например:
$ # 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 "~"
, это будет считаться удвоенным, и, следовательно, инъекция будет возможна сразу .
Правильно используйте eval
правильно: с проверкой.
case $1${1%%/*} in
([!~]*|"$1"?*[!-+_.[:alnum:]]*|"") ! :;;
(*/*) set "${1%%/*}" "${1#*/}" ;;
(*) set "$1"
esac&& eval "printf '%s\n' $1${2+/\"\$2\"}"
printf %q
оболочки избегает вещей безопаснее, чем я доверяю рукописному паролю проверки не иметь ошибок.
– Charles Duffy
13 December 2015 в 07:25
printf
является командой $PATH
'd.
– mikeserv
13 December 2015 в 07:29
bash
? Если это так, printf
является встроенным, и %q
гарантированно присутствует.
– Charles Duffy
13 December 2015 в 07:30
bash
достаточно, чтобы знать not i>, чтобы доверять ему. попробуйте: x=$(printf \\1); [ -n "$x" ] || echo but its not null!
– mikeserv
13 December 2015 в 07:35
Расширение (без каламбура) на ответы birryree's и 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
предназначены для поддержки имен файлов с пробелами. Возможно, есть более элегантное решение, но это то, что я смог придумать.
$(rm -rf .)
.
– Charles Duffy
7 September 2015 в 14:46
>
, хотя?
– Radon Rosborough
9 October 2016 в 19:06
Я считаю, что это то, что вы ищете
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
printf %q
не i> сбегает из ведущих тильд - почти соблазнительно записать это как ошибку, так как это ситуация, в которой она терпит неудачу в заявленной цели. Однако, тем временем, хороший звонок!
– Charles Duffy
21 August 2015 в 14:05
Как насчет этого:
path=`realpath "$1"`
Или:
path=`readlink -f "$1"`
realpath
в C. Например, вы можете сгенерировать исполняемый файл realpath.exe
с помощью bash и gcc из этой командной строки: gcc -o realpath.exe -x c - <<< $'#include <stdlib.h> \n int main(int c,char**v){char p[9999]; realpath(v[1],p); puts(p);}'
. ура
– olibre
24 October 2013 в 10:21
realpath "~"
в командной строке). realpath
и readlink
расширяют ссылки ..
, но для них ~
- просто простой старый символ; это не имеет никакого отношения к $HOME
.
– Quuxplusone
23 January 2014 в 20:31
${HOME}
наиболее привлекательным. Есть ли причина, чтобы не сделать это основной рекомендацией? В любом случае, спасибо! – sage 5 September 2013 в 16:21eval
- ужасное предложение, это действительно плохо, что он получает так много upvotes. Вы столкнетесь со всеми проблемами, когда значение переменной содержит метасимволы оболочки. – user2719058 31 August 2014 в 20:47$(rm -rf .)
– Charles Duffy 13 April 2015 в 20:19echo ${~root}
не дает никакого результата на zsh (mac os x) – Orwellophile 11 June 2015 в 00:59export test="~root/a b"; echo ${~test}
– Gyscos 15 July 2015 в 17:49