Как распечатать только определенные переменные (оболочка и/или переменные среды) в ударе

${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 оставляет этот случай открытым). Подобие этого случая с простыми присвоениями и рассеянная природа списка случаев, где Вам не нужны двойные кавычки, то, почему я рекомендую просто использовать двойные кавычки, если Вы действительно не хотите разделить и шарик.

58
13.04.2017, 15:37
8 ответов
[1120839] "Есть ли другие команды, которые печатают только переменные оболочки, без функций?"

В man bash, в разделе SHELL BUILTIN COMMANDS (в разделе set) сказано: "Примечание: [1121227]()[1121228] синтаксис порождает подоболочку, если вам не нравится форкинг, просто используйте более подробный вариант

51
27.01.2020, 19:32

Вот некоторые обходные решения:

$ comm -3 <(declare | sort) <(declare -f | sort)

разбивка:

  1. declare печатает каждую определенную переменную (экспортируемый или не) и функция.
  2. declare -f печать только функционирует.
  3. 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. Также подоболочка от канала и/или цикла добавляет некоторые дополнительные переменные.

32
27.01.2020, 19:32
  • 1
    делает Ваш declare ...| cut передайте повреждение по каналу, при отсутствии атрибутов для переменной? Я предполагаю это -- используется в этом случае, но я все еще обеспокоен. sed могло бы быть более безопасным, т.е. declare -p | sed 's/^.* \([^ ]\+\)$/\1/' –  jmtd 12.05.2011, 17:29
  • 2
    +1 для compgen :) –  RSFalcon7 07.03.2014, 01:55

typeset встроенный странно имеет опцию показать функции только (-f) но не показать параметры только. К счастью, typeset (или set) дисплеи все параметры перед всеми функциями, именами функций и названиями параметра не могут содержать новые строки или знаки "равно" и новые строки в значениях параметров, заключаются в кавычки (они появляются как \n). Таким образом, можно остановиться в первой строке, которая не содержит знак "равно":

set | awk -F '=' '! /^[0-9A-Z_a-z]+=/ {exit} {print $1}'

Это только печатает названия параметра; если Вы хотите значения, изменение print $1 кому: print $0.

Обратите внимание, что это печатает все названия параметра (параметры, и переменные используются синонимично здесь), не только переменные среды (“переменная среды” синонимична с “экспортируемыми параметрами”).

Обратите внимание также, что это предполагает, что нет никакой переменной среды с именем, которое не соответствует ограничениям удара на названия параметра. Такие переменные не могут быть созданы в ударе, но могли быть наследованы от среды, когда удар запускается:

env 'foo ()
{
  =oops' bash
13
27.01.2020, 19:32
  • 1
    ! Я даже не думал о просто остановке в первой строке, которая не имеет '='. +1 –  Steven D 27.10.2010, 06:34

Я не уверен, как можно сделать set распечатайте только переменные. Однако путем рассмотрения вывода set, Я смог придумать следующий, который, кажется, захватывает просто переменные:

$ set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" 

В основном я ищу строки, которые запускаются с букв, чисел или пунктуации, сопровождаемой "=". От вывода, который я видел, это захватывает все переменные; однако, я сомневаюсь, что это очень портативно.

Если, как Ваш заголовок предполагает, Вы хотите вычесть из этого списка переменные, которые экспортируются и таким образом получают список неэкспортируемых переменных, то Вы могли сделать что-то вроде этого

$ set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" | sort > ./setvars && env | sort | comm -23 ./setvars - 

Для разрушения этого немного вот то, что это делает:

  1. set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" | sort > ./setvars : Это, надо надеяться, получает все переменные (как обсуждено прежде), сортирует их и засовывает результат в файл.
  2. && env | sort: После того, как предыдущая команда завершена, мы собираемся звонить env и вид его вывод.
  3. | comm -23 ./setvars -: Наконец, мы передаем отсортированный вывод по каналу env в comm и используйте -23 опция распечатать строки, которые уникальны для первого аргумента, в этом случае строки, уникальные для нашего вывода от набора.

Когда Вы сделаны, Вы могли бы хотеть к очистке временный файл, который она создала с командой rm ./setvars

7
27.01.2020, 19:32
  • 1
    Проблемой с Вашей командой не является мобильность (это характерно для удара, конечно, но нет никакой проблемы на grep стороне). Проблема состоит в том, что Вы захватываете некоторые строки в функциональных определениях. Bash форматирует большую часть функционального кода, но не все это, в особенности не текст внутри здесь документы (f () {|cat <<EOF|foo=bar|EOF|} где | представляет разрыв строки). –  Gilles 'SO- stop being evil' 26.10.2010, 22:01

Просто используйте команду env. Это не печатает функции.

6
27.01.2020, 19:32
  • 1
    Это делает, если используется в сценарии. –  DocSalvager 05.09.2013, 16:08

Попробуйте команду printenv:

$printenv
2
27.01.2020, 19:32
  • 1
    printenv и ENV только печатают экспортируемый (среда), переменные и не неэкспортируемые (окружают) переменные. –  Lri 05.06.2013, 10:36

сравнение с чистой оболочкой, чтобы убедиться, что переменные из 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 будет слишком запутанной

0
27.01.2020, 19:32

В bash будут напечатаны только имена переменных:

compgen -v

Или, если нужны значения, используйте:

declare -p
2
27.01.2020, 19:32

Теги

Похожие вопросы