Могут ли выражения расширения параметра ${var} вставляться в bash?
Что у меня есть:
progname=${0%.*}
progname=${progname##*/}
Может ли это быть вложенным (или нет) в одну строку, т.е. одно выражение?
Я пытаюсь удалить путь и расширение из имени script, чтобы осталось только базовое имя. Вышеуказанные две строки работают нормально. Моя природа "С" просто заставляет меня запутывать их еще больше.
Ответы
Ответ 1
Если по гнезду вы имеете в виду что-то вроде этого:
#!/bin/bash
export HELLO="HELLO"
export HELLOWORLD="Hello, world!"
echo ${${HELLO}WORLD}
Тогда нет, вы не можете вложить выражения ${var}
. Расширитель синтаксиса bash не сможет его понять.
Однако, если я правильно понимаю вашу проблему, вы можете посмотреть на команду basename
- она удаляет путь из заданного имени файла, а если дано расширение, это также разделит. Например, запуск basename /some/path/to/script.sh .sh
вернет script
.
Ответ 2
Bash поддерживает косвенное расширение:
$ FOO_BAR="foobar"
$ foo=FOO
$ foobar=${foo}_BAR
$ echo ${foobar}
FOO_BAR
$ echo ${!foobar}
foobar
Это должно поддерживать вложенность, которую вы ищете.
Ответ 3
Старый поток, но, возможно, ответ заключается в использовании Indirection: ${! PARAMETER}
Например, рассмотрим следующие строки:
H="abc"
PARAM="H"
echo ${!PARAM} #gives abc
Ответ 4
Следующая опция сработала для меня:
NAME="par1-par2-par3"
echo $(TMP=${NAME%-*};echo ${TMP##*-})
Выход:
par2
Ответ 5
Это вложение не представляется возможным в bash, но оно работает в zsh:
progname=${${0%.*}##*/}
Ответ 6
На самом деле можно создать вложенные переменные в bash, используя два шага.
Вот тест script, основанный на записи Тима, используя идею, предложенную пользователем1956358.
#!/bin/bash
export HELLO="HELLO"
export HELLOWORLD="Hello, world!"
# This command does not work properly in bash
echo ${${HELLO}WORLD}
# However, a two-step process does work
export TEMP=${HELLO}WORLD
echo ${!TEMP}
Вывод:
Hello, world!
Есть много опрятных трюков, объясняемых при запуске ' info bash' из командной строки, затем поиск " Расширение параметров оболочки". Сегодня я читал несколько, просто потерял около 20 минут своего времени, но мои скрипты будут намного лучше...
Обновление: после более подробной информации я предлагаю эту альтернативу по вашему первоначальному вопросу.
progname=${0##*/}
Он возвращает
bash
Ответ 7
Выражения типа ${${a}}
не работают. Чтобы обойти это, вы можете использовать eval
:
b=value
a=b
eval aval=\$$a
echo $aval
Выход
value
Ответ 8
Я знаю, что это древняя нить, но вот мои 2 цента.
Здесь функция (по общему признанию kludgy) bash, которая позволяет использовать требуемые функции:
read_var() {
set | grep ^$1\\b | sed s/^$1=//
}
Здесь короткий тест script:
#!/bin/bash
read_var() {
set | grep ^$1\\b | sed s/^$1=//
}
FOO=12
BAR=34
ABC_VAR=FOO
DEF_VAR=BAR
for a in ABC DEF; do
echo $a = $(read_var $(read_var ${a}_VAR))
done
Выход, как и ожидалось:
ABC = 12
DEF = 34
Ответ 9
Базеальное имя bultin могло бы помочь в этом, так как вы специально разбиваете на/в одной части:
[email protected]# var=/path/to/file.extension
[email protected]# basename ${var%%.*}
file
[email protected]#
Это не намного быстрее, чем вариант с двумя линиями, но это только одна строка, использующая встроенные функции. Или, используйте zsh/ksh, который может делать объекты, вложенные в шаблон.:)
Ответ 10
Существует 1 строка решения исходного вопроса OP, базовое имя сценария с расширением файла:
progname=$(tmp=${0%.*} ; echo ${tmp##*/})
Здесь другое, но, используя чит для базового имени:
progname=$(basename ${0%.*})
Другие ответы отошли от исходного вопроса OP и сосредоточились на том, возможно ли просто расширить результат выражений с помощью ${!var}
но столкнулись с ограничением, что var
должен явно совпадать с именем переменной. Сказав это, ничто не помешает вам получить 1-строчный ответ, если вы объедините выражения вместе с точкой с запятой.
ANIMAL=CAT
BABYCAT=KITTEN
tmp=BABY${ANIMAL} ; ANSWER=${!tmp} # ANSWER=KITTEN
Если вы хотите, чтобы это выглядело как отдельный оператор, вы можете вложить его в подоболочку, т.е.
ANSWER=$( tmp=BABY${ANIMAL) ; echo ${!tmp} ) # ANSWER=KITTEN
Интересное использование - косвенные работы над аргументами функции bash. Затем вы можете вкладывать вызовы вашей функции bash для достижения многоуровневой вложенной косвенности, потому что нам разрешено делать вложенные команды:
Вот демонстрация косвенности выражения:
deref() { echo ${!1} ; }
ANIMAL=CAT
BABYCAT=KITTEN
deref BABY${ANIMAL} # Outputs: KITTEN
Вот демонстрация многоуровневой косвенности через вложенные команды:
deref() { echo ${!1} ; }
export AA=BB
export BB=CC
export CC=Hiya
deref AA # Outputs: BB
deref $(deref AA) # Outputs: CC
deref $(deref $(deref AA)) # Outputs: Hiya
Ответ 11
Если мотивация состоит в том, чтобы "обфускать" (я бы сказал, упростил) обработку массива в духе "понимания" Python, создайте вспомогательную функцию, которая выполняет последовательности операций.
function fixupnames()
{
pre=$1 ; suf=$2 ; shift ; shift ; args=([email protected])
args=(${args[@]/#/${pre}-})
args=(${args[@]/%/-${suf}})
echo ${args[@]}
}
Вы можете использовать результат с хорошим однострочным.
$ echo $(fixupnames a b abc def ghi)
a-abc-b a-def-b a-ghi-b
Ответ 12
Хотя это очень старая тема, это устройство идеально подходит для прямого или случайного выбора файла/каталога для обработки (воспроизведения мелодий, выбора фильма для просмотра или книги для чтения и т.д.).
В bash я считаю, что в целом верно, что вы не можете напрямую вкладывать любые два расширения одного и того же типа, но если вы можете разделить их каким-либо другим видом расширения, это можно сделать.
e=($(find . -maxdepth 1 -type d))
c=${2:-${e[$((RANDOM%${#e[@]}))]}}
Объяснение: e - это массив имен каталогов, c выбранный каталог, либо явно названный как $ 2,
${2:-...}
где... альтернативный случайный выбор, заданный
${e[$((RANDOM%${#e[@]}))]}
где
$((RANDOM%...))
число, сгенерированное bash, делится на количество элементов в массиве e, определяемое как
${#e[@]}
получая остаток (от оператора%), который становится индексом для массива e
${e[...]}
Таким образом, у вас есть четыре вложенных расширения.
Ответ 13
Это сработает, если вы будете следовать приведенному ниже способу выполнения промежуточного шага:
export HELLO="HELLO"
export HELLOWORLD="Hello, world!"
varname=${HELLO}WORLD
echo ${!varname}
Ответ 14
eval позволит вам делать то, что вы хотите:
export HELLO="HELLO"
export HELLOWORLD="Hello, world!"
eval echo "\${${HELLO}WORLD}"
Выход: Hello, world