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

Набор встроенных команд bash, если вызывается без аргументов, будет печатать все переменные оболочки и среды, но также и все определенные функции. Это делает выход непригодным для людей и трудным для grep .

Как я могу заставить bash встроенный set команд печатать только переменные, а не функции?

Существуют ли другие команды, которые печатают только переменные оболочки без функций?

Примечание: bash различает переменные оболочки и переменные среды. см. здесь Разница между переменными окружения и экспортированными переменными среды в bash

«Существуют ли другие команды, которые печатают только переменные оболочки без функций?»

В man bash в разделе SHELL BUILTIN COMMANDS (в заданном разделе) говорится: «В режиме posix перечислены только переменные оболочки».

 (set -o posix; set) 

Вот некоторые обходные пути:

 $ 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='()' ... 

Вы можете отрезать атрибуты, используя … cut:

 $ 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 

Преимущество: это чистое решение bash. Недостаток: некоторые значения перепутаны из-за интерпретации через printf . Также подоболочка из трубы и / или цикла добавляет некоторые дополнительные переменные.

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

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

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

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

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

 env 'foo () { =oops' bash 

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

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

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

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

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

Чтобы немного сломать это, вот что он делает:

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

Когда вы закончите, вы можете rm ./setvars файл temp, который он создал, с помощью команды rm ./setvars

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

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

 $printenv 

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