${VAR}
и $VAR
точно эквивалентны. Для простого переменного расширения, единственная причина использовать ${VAR}
когда парсинг иначе захватил бы слишком много символов в имя переменной, как в ${VAR1}_$VAR2
(который без фигурных скобок был бы эквивалентен ${VAR1_}$VAR2
). Большинство украшенных расширений (${VAR:=default}
, ${VAR#prefix}
, …), требуют фигурных скобок.
В переменном присвоении полевое разделение (т.е. разделение в пробеле в значении) и расширение пути (т.е. globbing) выключены, таким образом, VAR=$VAR1
точно эквивалентно VAR="$VAR1"
, во всех оболочках POSIX и во всем предPOSIX sh, что я услышал о. (POSIX касательно: простые команды). По той же причине, VAR=*
надежно наборы VAR
к литеральной строке *
; конечно, VAR=a b
наборы VAR
кому: a
начиная с b
отдельное слово во-первых. Вообще говоря, двойные кавычки являются ненужными, где синтаксис оболочки ожидает отдельное слово, например, в case … in
(но не в шаблоне), но даже там необходимо быть осторожными: например, POSIX указывает то перенаправление цели (>$filename
) не требуйте заключения в кавычки в сценариях, но несколько оболочек включая удар действительно требуют двойных кавычек даже в сценариях. Посмотрите, Когда двойное заключение в кавычки будет необходимо? для более полного анализа.
Вам действительно нужны двойные кавычки в других случаях, в особенности в export VAR="${VAR1}"
(который может эквивалентно быть записан export "VAR=${VAR1}"
) во многих оболочках (POSIX оставляет этот случай открытым). Подобие этого случая с простыми присвоениями и рассеянная природа списка случаев, где Вам не нужны двойные кавычки, то, почему я рекомендую просто использовать двойные кавычки, если Вы действительно не хотите разделить и шарик.
В man bash, в разделе SHELL BUILTIN COMMANDS (в разделе set) сказано: "Примечание: [1121227]()[1121228] синтаксис порождает подоболочку, если вам не нравится форкинг, просто используйте более подробный вариант
Вот некоторые обходные решения:
$ comm -3 <(declare | sort) <(declare -f | sort)
разбивка:
declare
печатает каждую определенную переменную (экспортируемый или не) и функция.declare -f
печать только функционирует.comm -3
удалит все строки, характерные для обоих. В действительности это удалит функции, оставляя только переменные.Чтобы только распечатать переменные, которые не экспортируются:
$ comm -3 <(comm -3 <(declare | sort) <(declare -f | sort)) <(env | sort)
Другое обходное решение:
$ declare -p
Это только распечатает переменные, но с некоторыми ужасными атрибутами.
declare -- BASH="/bin/bash"
declare -ir BASHPID=""
declare -A BASH_ALIASES='()'
declare -a BASH_ARGC='()'
...
Можно сократить атрибуты далеко с помощью... сокращение:
$ declare -p | cut -d " " -f 3
Одна оборотная сторона - то, что значение IFS интерпретируется вместо отображенного.
сравните:
$ comm -3 <(declare | sort) <(declare -f | sort)
...
IFS=$' \t\n'
...
$ declare -p | cut -d " " -f 3
...
IFS="
"
...
Это делает его довольно трудно для использования того вывода для последующей обработки, из-за этого одинокой "
в одной строке. Возможно, некоторая IFS-fu может быть сделана для предотвращения этого.
Еще одно обходное решение, с помощью compgen
:
$ compgen -v
Встроенный удар compgen
был предназначен, чтобы использоваться в сценариях завершения. С этой целью, compgen -v
списки все определенные переменные. Оборотная сторона: это перечисляет только имена переменной, не значения.
Вот взлом, чтобы также перечислить значения.
$ compgen -v | while read var; do printf "%s=%q\n" "$var" "${!var}"; done
Преимущество: это - чистое решение для удара. Недостаток: некоторые значения испорчены из-за интерпретации через printf
. Также подоболочка от канала и/или цикла добавляет некоторые дополнительные переменные.
declare ...| cut
передайте повреждение по каналу, при отсутствии атрибутов для переменной? Я предполагаю это --
используется в этом случае, но я все еще обеспокоен. sed
могло бы быть более безопасным, т.е. declare -p | sed 's/^.* \([^ ]\+\)$/\1/'
– jmtd
12.05.2011, 17:29
typeset
встроенный странно имеет опцию показать функции только (-f
) но не показать параметры только. К счастью, typeset
(или set
) дисплеи все параметры перед всеми функциями, именами функций и названиями параметра не могут содержать новые строки или знаки "равно" и новые строки в значениях параметров, заключаются в кавычки (они появляются как \n
). Таким образом, можно остановиться в первой строке, которая не содержит знак "равно":
set | awk -F '=' '! /^[0-9A-Z_a-z]+=/ {exit} {print $1}'
Это только печатает названия параметра; если Вы хотите значения, изменение print $1
кому: print $0
.
Обратите внимание, что это печатает все названия параметра (параметры, и переменные используются синонимично здесь), не только переменные среды (“переменная среды” синонимична с “экспортируемыми параметрами”).
Обратите внимание также, что это предполагает, что нет никакой переменной среды с именем, которое не соответствует ограничениям удара на названия параметра. Такие переменные не могут быть созданы в ударе, но могли быть наследованы от среды, когда удар запускается:
env 'foo ()
{
=oops' bash
Я не уверен, как можно сделать set
распечатайте только переменные. Однако путем рассмотрения вывода set
, Я смог придумать следующий, который, кажется, захватывает просто переменные:
$ set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+="
В основном я ищу строки, которые запускаются с букв, чисел или пунктуации, сопровождаемой "=". От вывода, который я видел, это захватывает все переменные; однако, я сомневаюсь, что это очень портативно.
Если, как Ваш заголовок предполагает, Вы хотите вычесть из этого списка переменные, которые экспортируются и таким образом получают список неэкспортируемых переменных, то Вы могли сделать что-то вроде этого
$ set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" | sort > ./setvars && env | sort | comm -23 ./setvars -
Для разрушения этого немного вот то, что это делает:
set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" | sort > ./setvars
: Это, надо надеяться, получает все переменные (как обсуждено прежде), сортирует их и засовывает результат в файл.&& env | sort
: После того, как предыдущая команда завершена, мы собираемся звонить env
и вид его вывод.| comm -23 ./setvars -
: Наконец, мы передаем отсортированный вывод по каналу env
в comm
и используйте -23
опция распечатать строки, которые уникальны для первого аргумента, в этом случае строки, уникальные для нашего вывода от набора.Когда Вы сделаны, Вы могли бы хотеть к очистке временный файл, который она создала с командой rm ./setvars
f () {|cat <<EOF|foo=bar|EOF|}
где |
представляет разрыв строки).
– Gilles 'SO- stop being evil'
26.10.2010, 22:01
сравнение с чистой оболочкой, чтобы убедиться, что переменные из rc-скриптов также исключены
## get mostly local vars
diff_env(){
diff <(bash -cl 'set -o posix && set') \
<(set -o posix && set && set +o posix) | \
grep -E "^>|^\+" | \
grep -Ev "^(>|\+|\+\+) ?(BASH|COLUMNS|LINES|HIST|PPID|SHLVL|PS(1|2)|SHELL|FUNC)" | \
sed -r 's/^> ?|^\+ ?//'
}
версия с comm
будет слишком запутанной
В bash будут напечатаны только имена переменных:
compgen -v
Или, если нужны значения, используйте:
declare -p