Указатель NULL
- это тот, который указывает на никуда. Когда вы разыскиваете указатель p
, вы говорите «дайте мне данные в месте, хранящемся в« p ». Когда p
является нулевым указателем, местоположение, хранящееся в p
, является nowhere
, вы говорите «Дайте мне данные в месте« нигде ». Очевидно, он не может этого сделать, поэтому он выбрасывает NULL pointer exception
.
В общем, это потому, что что-то не было правильно инициализировано.
Если в гнезде вы имеете в виду что-то вроде этого:
#!/bin/bash
export HELLO="HELLO"
export HELLOWORLD="Hello, world!"
echo ${${HELLO}WORLD}
Тогда нет, вы не можете вставлять выражения ${var}
. Расширитель синтаксиса bash не поймет этого.
Однако, если я правильно понимаю вашу проблему, вы можете посмотреть на команду basename
- она удаляет путь из заданного имени файла, и если задано расширение, также разделит это. Например, запуск basename /some/path/to/script.sh .sh
вернет script
.
basename bultin может помочь с этим, поскольку вы специально раскалываете / в одной части:
user@host# var=/path/to/file.extension
user@host# basename ${var%%.*}
file
user@host#
Это не намного быстрее, чем вариант с двумя линиями, но это всего лишь одна строка, использующая встроенная функциональность. Или, используйте zsh / ksh, который может делать объекты, вложенные в шаблон. :)
Старая нить, но, возможно, ответ - использование Indirection: $ {! PARAMETER}
Например, рассмотрим следующие строки:
H="abc"
PARAM="H"
echo ${!PARAM} #gives abc
Я знаю, что это древняя тема, но вот мои 2 цента.
Вот функция bash (по общему признанию kludgy), которая позволяет использовать требуемые функции:
read_var() {
set | grep ^$1\\b | sed s/^$1=//
}
Вот короткий тестовый скрипт:
#!/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
Выражения вроде ${${a}}
не работают. Чтобы обойти это, вы можете использовать eval
:
b=value
a=b
eval aval=\$$a
echo $aval
Выход:
value
eval позволит вам делать то, что вы хотите:
export HELLO="HELLO"
export HELLOWORLD="Hello, world!"
eval echo "\${${HELLO}WORLD}"
Выход: Hello, world
На самом деле можно создать вложенные переменные в bash, используя два шага.
Вот тестовый скрипт, основанный на записи Тима, используя идею, предложенную пользователем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» из командной строки, а затем поиск «Расширение параметра Shell». Сегодня я читал несколько, просто потерял около 20 минут своего времени, но мои скрипты будут намного лучше ...
Обновление: после более подробного изучения я предлагаю эту альтернативу за ваш начальный вопрос.
progname=${0##*/}
Он возвращает
bash
Для меня работал следующий параметр:
NAME="par1-par2-par3"
echo $(TMP=${NAME%-*};echo ${TMP##*-})
Выход:
par2
echo
он рассматривает par2
как команду?
– A S
16 April 2018 в 00:17
Это вложение не представляется возможным в bash, но оно работает в zsh:
progname=${${0%.*}##*/}
Если мотивация состоит в том, чтобы «обфускать» (я бы сказал, упростил) обработку массива в духе «понимания» Python, создайте вспомогательную функцию, которая выполняет последовательности операций.
function fixupnames()
{
pre=$1 ; suf=$2 ; shift ; shift ; args=($@)
args=(${args[@]/#/${pre}-})
args=(${args[@]/%/-${suf}})
echo ${args[@]}
}
Вы может использовать результат с хорошим однострочным.
$ echo $(fixupnames a b abc def ghi)
a-abc-b a-def-b a-ghi-b
Bash поддерживает косвенное расширение:
$ FOO_BAR="foobar"
$ foo=FOO
$ foobar=${foo}_BAR
$ echo ${foobar}
FOO_BAR
$ echo ${!foobar}
foobar
Это должно поддерживать вложенность, которую вы ищете.
В исходном вопросе OP есть однострочное решение, базовое имя скрипта с расширением файла:
progname=$(tmp=${0%.*} ; echo ${tmp##*/})
Вот еще один, но, используя чит для basename:
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
deref()
? Если у вас это объявлено, вы можете иметь свой oneliner без временной переменной?
– Stephen Quan
7 February 2018 в 00:48
Хотя это очень старый поток, это устройство идеально подходит для прямого или случайного выбора файла / каталога для обработки (воспроизведения мелодий, выбора фильма для просмотра или книги для чтения и т. д.).
В 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[...]}
Таким образом, у вас есть четыре вложенных разложения.
ARR=('foo' 'bar' 'bogus'); i=0; while /bin/true ; do echo ${ARR[$i]} ; i=(( (i + 1) % 3 )); done
, который, очевидно, бесполезен как код, но работает в качестве примера. – Ian Stapleton Cordasco 7 January 2013 в 23:58bash
иksh
. Это работает:x=yyy; y=xxxyyy; echo ${y%${x}}
. Я думаю, что важный бит состоит в том, что вложенное расширение является аргументом одного из операторов. Однако я не видел, что это хорошо документировано. – twalberg 8 January 2013 в 00:07echo ${${HELLO}WORLD}
показана невозможность this i>. – Atcold 27 February 2017 в 21:25