Як надрукувати лише задані змінні (оболонки та / або змінні середовища) в bash


57

Команда bash buildin set, якщо її викликати без аргументів, буде друкувати всі змінні оболонки та середовища, а також усі визначені функції. Це робить вихід непридатним для людини і важким grep.

Як я можу змусити команду bash вбудовану setдрукувати лише змінні, а не функції?

Чи є інші команди, які друкують тільки змінні оболонки, без функцій?

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

Відповіді:


51

"Чи є інші команди, які друкують тільки змінні оболонки, без функцій?"

У man bash, у розділі SHELL BUILTIN COMMANDS (у розділі set) написано: "У режимі posix перераховані лише змінні оболонки".

(set -o posix; set)

Примітка: ()синтаксис породжує нижню частину корпусу, якщо вам не подобається розщеплення, просто скористайтеся більш детальною версією

set -o posix; set; set +o posix

1
На сьогодні найкраще рішення
Руслан

1
Починається купа зазвичай нецікавих змінних _, від яких легко позбутися:(set -o posix ; set | grep -v ^_)
hyde

Це мене так довго турбує! Відсікання рядків, які починаються з _, недостатньо, якщо у вас є багаторядкові значення, воно все одно залишатиме вміст значення в такті. Оскільки набір друкує рядки в порядку, всі _ рядки будуть наприкінці, тож ви можете просто вирізати результати після першого рядка _, використовуючи:set -o posix; set | sed -e '/^_/,$d'; set +o posix;
Скотт

1
Лише зауваження: дужки важливі в (set -o posix; set). Без дужок поведінку поточної оболонки Bash було б змінено відповідно до стандарту Posix. (Не знаю, що це означає, але це виглядає важливо.) З дужками Bash залишається незмінним.
Джон Ред

1
Побічні ефекти : Встановлює POSIXLY_CORRECT=yта додає posixдо$SHELLOPTS
Tom Hale

31

Ось кілька вирішень:

$ 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-фу можна зробити для запобігання цього.


Ще одне вирішення, використовуючи 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

+1 для compgen:)
RSFalcon7

13

Як 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

Чудове рішення! Я навіть не думав просто зупинятися на першому рядку, у якому немає '='. +1
Стівен D

Рівно, з sed: set | sed '/=/!Q'
Toby Speight

7

Я не впевнений, як можна 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


Проблема з вашою командою полягає не в портативності (звичайно, вона характерна для bash, але немає жодної проблеми на стороні grep). Проблема полягає в тому, що ви захоплюєте деякі рядки у визначеннях функцій. Bash віддає більшу частину коду функції, але не весь, зокрема не текст, який міститься тут, у документах ( f () {|cat <<EOF|foo=bar|EOF|}де |представлено розрив рядка).
Жил "ТАК - перестань бути злим"

6

Просто використовуйте команду env. Він не друкує функції.


1
Це робиться, якщо використовується всередині сценарію.
DocSalvager

2

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

$printenv

6
printtenv та env тільки друковані експортні (середовище) змінні, а не неекспортовані (оболонки) змінні.
Лрі

@Lri Дякую! Мені було цікаво, як роздрукувати лише експортовані змінні.
Марк Стюарт

1

У bash, це буде друкувати лише імена змінних:

compgen -v

Або, якщо потрібні також значення, використовуйте:

declare -p

дякую за ваші зусилля. зауважте, що я вже згадував про таку можливість у своїй відповіді unix.stackexchange.com/a/5691/1170 в будь-якому разі є голосуванням.
lesmana

0

що відрізняється від чистої оболонки, щоб також залишитися без змін у сценаріїв 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

Прийнята відповідь чудова. Я пропоную альтернативу, яка не передбачає встановлення режиму POSIX:

Ось методика, яку я використовував для зберігання стану функції у файл, щоб я міг продовжувати його пізніше. Перший створює дамп стану, а другий створює лише список імен змінних.

set 2>/dev/null | while read a; do [[ $a == *=* ]] || break; echo $a; done 

set 2>/dev/null | while read a; do [[ $a == *=* ]] || break; echo ${a/=*}; done 

Обидва працюють, скидаючи лінії, поки не знайдуть одну без знака '=', що виникає при переліку першої функції. Останній завершує виконання завдання.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.