У меня есть переменная в моем сценарии bash, значение которой примерно такое:
~/a/b/c
Обратите внимание, что это нерасширенная тильда. Когда я выполняю ls -lt для этой переменной (назовем ее $ VAR), я не получаю такой каталог. Я хочу, чтобы bash интерпретировал / расширял эту переменную, не выполняя ее. Другими словами, я хочу, чтобы bash запускал eval, но не запускал оцениваемую команду. Возможно ли это в баше?
Как мне удалось передать это в мой скрипт без расширения? Я передал аргумент, заключив его в двойные кавычки.
Попробуйте эту команду, чтобы понять, что я имею в виду:
ls -lt "~"
Это как раз та ситуация, в которой я нахожусь. Я хочу, чтобы тильда была расширена. Другими словами, на что мне заменить magic, чтобы эти две команды стали идентичными:
ls -lt ~/abc/def/ghi
и
ls -lt $(magic "~/abc/def/ghi")
Обратите внимание, что ~ / abc / def / ghi может существовать, а может и не существовать.
источник
eval
.foo=~/"$filepath"
илиfoo="$HOME/$filepath"
dir="$(readlink -f "$dir")"
Ответы:
Из-за характера StackOverflow я не могу просто сделать этот ответ неприемлемым, но за прошедшие 5 лет с тех пор, как я опубликовал это, были ответы намного лучше, чем мой, по общему признанию, элементарный и довольно плохой ответ (я был молод, не убивай меня).
Другие решения в этой теме - более безопасные и лучшие решения. Я бы предпочел любой из этих двух:
Оригинальный ответ для исторических целей (но, пожалуйста, не используйте это)
Если я не ошибаюсь,
"~"
сценарий bash не будет расширять его таким образом, потому что он рассматривается как буквальная строка"~"
. Вы можете принудительно расширить с помощьюeval
этого.Или просто используйте,
${HOME}
если хотите домашний каталог пользователя.источник
${HOME}
наиболее привлекательным. Есть ли причина не делать это своей основной рекомендацией? В любом случае спасибо!eval
- ужасное предложение, очень плохо, что оно набирает столько голосов. Вы столкнетесь со всевозможными проблемами, если значение переменной будет содержать метасимволы оболочки.Если переменная
var
вводится пользователем,eval
должен не использоваться для расширения тильды с использованиемПричина в том, что пользователь мог случайно (или намеренно) ввести, например,
var="$(rm -rf $HOME/)"
с возможными катастрофическими последствиями.Лучше (и безопаснее) использовать расширение параметра Bash:
источник
#
в"${var/#\~/$HOME}"
?$var
.\~
убегать~
? (2) Ваш ответ предполагает, что~
это первый символ в$var
. Как мы можем игнорировать начальные пробелы в$var
?:
символом в строке без кавычек. Больше информации в документации . Чтобы удалить начальные пробелы, см. Раздел Как обрезать пробелы в переменной Bash?Плагируя себя из предыдущего ответа , чтобы сделать это надежно без рисков безопасности, связанных с
eval
:...используется в качестве...
В качестве альтернативы можно использовать более простой подход с
eval
осторожным использованием :источник
printf %q
чтобы избежать все , кроме тильды, а затем использоватьeval
без риска.Безопасный способ использования eval - это
"$(printf "~/%q" "$dangerous_path")"
. Обратите внимание, что это специфично для bash.Посмотреть этот вопрос для подробностей
Также обратите внимание, что в zsh это будет так же просто, как
echo ${~dangerous_path}
источник
echo ${~root}
не выводить на zsh (mac os x)export test="~root/a b"; echo ${~test}
Как насчет этого:
Или:
источник
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);}'
. Cheersrealpath ~
->/home/myhome
<workingdir>/~
.Расширение (без каламбура) ответов birryree и halloleo: общий подход заключается в использовании
eval
, но он имеет некоторые важные оговорки, а именно пробелы и перенаправление вывода (>
) в переменной. Мне кажется, работает следующее:Попробуйте использовать каждый из следующих аргументов:
объяснение
${mypath//>}
Полоски из>
символов , которые могут затирать файл во времяeval
.eval echo ...
что делает фактическое расширение тильды-e
Аргумент заключен в двойные кавычки для поддержки имен файлов с пробелами.Возможно, есть более элегантное решение, но это то, что мне удалось придумать.
источник
$(rm -rf .)
.>
символы?Я считаю, что это то, что ты ищешь
Пример использования:
источник
printf %q
не избегает ведущих тильд - почти соблазнительно зарегистрировать это как ошибку, поскольку это ситуация, в которой она не выполняет заявленную цель. Тем не менее, пока что хороший звонок!Вот мое решение:
источник
echo
средства, которыеexpandTilde -n
не будут вести себя так, как ожидалось, и поведение с именами файлов, содержащими обратную косую черту, не определено POSIX. См. Pubs.opengroup.org/onlinepubs/009604599/utilities/echo.htmlПросто используйте
eval
правильно: с проверкой.источник
printf %q
безопасно избегает вещей больше, чем я верю, что рукописный код проверки не содержит ошибок ,printf
это$PATH
команда 'd.bash
? Если да, тоprintf
это встроенная функция,%q
которая гарантированно присутствует.bash
достаточно, чтобы знать, что ему нельзя доверять. попробуйте:x=$(printf \\1); [ -n "$x" ] || echo but its not null!
Вот функция POSIX эквивалент Bash Хакон Hægland в ответ
2017-12-10 редактирование: добавить
'%s'
за @CharlesDuffy в комментарии.источник
printf '%s\n' "$tilde_less"
возможно? В противном случае он будет вести себя неправильно, если расширяемое имя файла будет содержать обратную косую черту%s
, или другой синтаксис, имеющий значение дляprintf
. В остальном, однако, это отличный ответ - правильный (когда расширения bash / ksh не нужно покрывать), очевидно безопасный (без гаданияeval
) и краткий.почему бы не углубиться в получение домашнего каталога пользователя с помощью getent?
источник
Просто чтобы расширить ответ birryree для путей с пробелами: вы не можете использовать
eval
команду как есть, потому что она разделяет оценку пробелами. Одно из решений - временно заменить пробелы для команды eval:Этот пример, конечно, основан на предположении, что он
mypath
никогда не содержит последовательность символов"_spc_"
.источник
$(rm -rf .)
Возможно, вам будет проще сделать это в Python.
(1) Из командной строки unix:
Результаты в:
(2) В сценарии bash как одноразовый - сохраните это как
test.sh
:Запуск
bash ./test.sh
результатов в:(3) В качестве утилиты - сохраните это
expanduser
где-нибудь на своем пути с разрешениями на выполнение:Затем это можно было бы использовать в командной строке:
Или в скрипте:
источник
echo $thepath
глючит; необходимоecho "$thepath"
исправить менее редкие случаи (имена с табуляцией или пробелами преобразуются в одиночные пробелы; имена с расширенными глобусами) илиprintf '%s\n' "$thepath"
также исправить необычные (например, файл с именем-n
или файл с литералы обратной косой черты в XSI-совместимой системе). Точно так жеthepath=$(expanduser "$1")
echo
вести себя полностью определяемым реализацией образом, если какой-либо аргумент содержит обратную косую черту; необязательные расширения XSI для POSIX предписывают поведение по умолчанию (не требуется-e
или не-E
требуется) расширения для таких имен.Самый простой : замените «магия» на «eval echo».
Проблема: вы столкнетесь с проблемами с другими переменными, потому что eval - зло. Например:
Обратите внимание, что проблема с инъекцией не возникает при первом расширении. Итак, если вы просто замените
magic
наeval echo
, все будет в порядке. Но если вы это сделаетеecho $(eval echo ~)
, это будет восприимчиво к инъекции.Точно так же, если вы сделаете
eval echo ~
вместоeval echo "~"
, это будет считаться двойным расширением, и поэтому инъекция станет возможной сразу.источник
s='echo; EVIL_COMMAND'
. (Это не удастся, потомуEVIL_COMMAND
что не существует на вашем компьютере. Но если бы эта команда была,rm -r ~
например, она бы удалила ваш домашний каталог.)Я сделал это с помощью подстановки переменных параметров после прочтения пути с помощью read -e (среди прочего). Таким образом, пользователь может заполнить путь табуляцией, и если пользователь введет путь ~, он будет отсортирован.
Дополнительным преимуществом является то, что при отсутствии тильды с переменной ничего не происходит, а если тильда есть, но не в первой позиции, она также игнорируется.
(Я включаю -i для чтения, так как использую его в цикле, чтобы пользователь мог исправить путь в случае возникновения проблемы.)
источник