Как вручную развернуть специальную переменную (например, ~ тильда) в Bash - PullRequest
114 голосов
/ 19 октября 2010

В моем скрипте 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 может существовать или не существовать.

Ответы [ 14 ]

0 голосов
/ 19 июня 2019

Я сделал это с подстановкой параметров переменной после чтения в пути с использованием read -e (среди прочего). Таким образом, пользователь может завершить путь путем табуляции, и если пользователь вводит ~ путь, он сортируется.

read -rep "Enter a path:  " -i "${testpath}" testpath 
testpath="${testpath/#~/${HOME}}" 
ls -al "${testpath}" 

Дополнительным преимуществом является то, что если тильды нет, с переменной ничего не происходит, и если тильда есть, но не в первой позиции, она также игнорируется.

(я включаю -i для чтения, так как я использую это в цикле, чтобы пользователь мог исправить путь в случае возникновения проблемы.)

0 голосов
/ 25 января 2017

Простейший : замените 'магию' на '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 "~", это будет считаться вдвое больше, и, следовательно, инъекция будет возможна сразу.

0 голосов
/ 28 октября 2015

Это может показаться проще в 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
0 голосов
/ 26 декабря 2011

Просто для расширения ответа 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_".

...