Можно ли вкладывать выражения расширения $ {var} в bash? - PullRequest
55 голосов
/ 27 мая 2009

Что у меня есть это:

progname=${0%.*}
progname=${progname##*/}

Может ли это быть вложено (или нет) в одну строку, то есть в одно выражение?

Я пытаюсь убрать путь и расширение из имени скрипта, чтобы осталось только базовое имя. Выше две строки работают нормально. Моя природа «С» просто заставляет меня запутывать их еще больше.

Ответы [ 14 ]

42 голосов
/ 27 мая 2009

Если под гнездом вы подразумеваете что-то вроде этого:

#!/bin/bash

export HELLO="HELLO"
export HELLOWORLD="Hello, world!"

echo ${${HELLO}WORLD}

Тогда нет, вы не можете вкладывать ${var} выражения. Расширитель синтаксиса bash этого не поймет.

Однако, если я правильно понимаю вашу проблему, вы можете посмотреть на использование команды basename - она ​​удаляет путь из заданного имени файла и, если дано расширение, также удаляет это. Например, выполнение basename /some/path/to/script.sh .sh вернет script.

39 голосов
/ 08 января 2013

Bash поддерживает косвенное расширение:

$ FOO_BAR="foobar"
$ foo=FOO
$ foobar=${foo}_BAR
$ echo ${foobar}
FOO_BAR
$ echo ${!foobar}
foobar

Это должно поддерживать вложение, которое вы ищете.

11 голосов
/ 18 февраля 2016

У меня сработал следующий параметр:

NAME="par1-par2-par3"
echo $(TMP=${NAME%-*};echo ${TMP##*-})

Вывод:

par2
11 голосов
/ 16 декабря 2015

Старый поток, но, возможно, ответом является использование Indirection: $ {! PARAMETER}

Например, рассмотрим следующие строки:

H="abc"
PARAM="H"
echo ${!PARAM} #gives abc
6 голосов
/ 10 января 2013

На самом деле в 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 ' из командной строки и поиском ' Расширения параметров оболочки '. Я сам сегодня читал несколько, просто потерял около 20 минут моего дня, но мои сценарии станут намного лучше ...

Обновление: после прочтения я предлагаю эту альтернативу для вашего первоначального вопроса.

progname=${0##*/}

Возвращает

bash
6 голосов
/ 27 мая 2009

Это вложение не представляется возможным в bash, но оно работает в zsh:

progname=${${0%.*}##*/}
3 голосов
/ 07 апреля 2013

Выражения типа ${${a}} не работают. Чтобы обойти это, вы можете использовать eval:

b=value
a=b
eval aval=\$$a
echo $aval

Выход

value

2 голосов
/ 16 августа 2012

Я знаю, что это древняя нить, но вот мои 2 цента.

Вот (по общему признанию, грязная) функция bash, которая обеспечивает необходимую функциональность:

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
1 голос
/ 24 апреля 2017

Существует 1-строчное решение исходного вопроса ОП, базовое имя сценария с расширением файла:

progname=$(tmp=${0%.*} ; echo ${tmp##*/})

Вот еще один, но, используя чит для базового имени:

progname=$(basename ${0%.*})

Другие ответы отошли от исходного вопроса ОП и сосредоточились на том, возможно ли просто расширить результат выражений с помощью ${!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
1 голос
/ 27 мая 2009

Базовое имя bultin может помочь в этом, так как вы специально разбиваете на / на одну часть:

user@host# var=/path/to/file.extension
user@host# basename ${var%%.*}
file
user@host#

Это на самом деле не быстрее, чем двухстрочный вариант, но это всего лишь одна строка, использующая встроенную функциональность. Или используйте zsh / ksh, который может выполнять вложение шаблонов. :)

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