оболочка posix: вывод списка имен переменных среды (без значений)

11

Как posix-совместимый способ, который работает с несколькими реализациями, как я могу напечатать список в настоящее время определенной переменной среды без их значений?

В некоторых реализациях (mksh, freebsd / bin / sh) простое использование exportподойдет:

$ export
FOO2
FOO

Но для некоторых других реализаций (bash, zsh, dash) exportтакже показано значение. С bash, например:

$ export
export FOO2='as  df\
  asdk=fja:\
asd=fa\
asdf'
export FOO='sjfkasjfd  kjasdf:\
   asdkj=fkajdsf:\
       :askjfkajsf=asdfkj:\
   safdkj'
$ printenv | sed -n l
FOO2=as\tdf\$
  asdk=fja:\$
asd=fa\$
asdf$
FOO=sjfkasjfd  kjasdf:\$
   asdkj=fkajdsf:\$
\t:askjfkajsf=asdfkj:\$
   safdkj$

Другие опции, такие как envили printenvне имеют возможности печатать только имена переменных без значений, по крайней мере, не на платформах linux и freebsd, которые я пробовал.

Трубопровод к awk / sed / etc. или урезание списка методами расширения параметров (например, ${foo%%=*}) приемлемо, но оно должно работать со значениями, которые могут занимать строки и иметь =пробел в значении (см. пример выше).

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

Juan
источник
2
Если вы собираетесь что-то анализировать, перейдите к выводу, export -pкоторый указан в POSIX, чтобы сгенерировать вывод, который также подходит для ввода в оболочке.
Кусалананда
Мне не нужно ничего вводить в оболочку. Я просто хочу имена переменных среды. Таким образом, лишняя фраза (например, слово «экспорт» в начале каждой строки) просто должна быть удалена в любом случае. Почему я хочу использовать export -pдля этого?
Хуан
1
Вы хотели бы использовать, export -pпотому что это даст вам согласованный вывод для всех оболочек POSIX, что вы сказали, что вы хотели.
Кусалананда
Я хочу решение, которое будет печатать только имена переменных, которое является согласованным решением для всех оболочек. export -pне соответствует первому требованию - печать только имен переменных без значений.
Хуан
Если вы собираетесь что-то анализировать, переходите к выводу export -p. Я не собираюсь писать этот разбор, потому что в общем случае он должен был бы также выполнить правильный разбор кавычек, если у вас есть переменная, значение которой является чем-то вроде hello\nexport var=value. Одной из немногих других команд, которая даст вам согласованный вывод во всех оболочках POSIX, является env, но этот вывод сложнее проанализировать, поскольку в нем отсутствует export =бит.
Кусалананда

Ответы:

9

Это довольно легко в awk.

awk 'BEGIN{for(v in ENVIRON) print v}'

Однако остерегайтесь некоторых реализаций AWK добавить переменные окружения своих собственных (например , GNU AWK добавляет AWKPATHи AWKLIBPATHк ENVIRON).

Вывод будет неоднозначным, если имя переменной среды содержит символ новой строки, что крайне необычно, но технически возможно. Чистое решение будет трудно. Лучше всего начать с того, что export -pмассировать его в чистом виде сложно. Вы можете использовать sed, чтобы массировать вывод export -p, а затем использовать, evalчтобы получить оболочку, чтобы удалить то, что она цитирует. Bash и Zsh печатают нестандартные префиксы.

report () { echo "${1%%=*}"; };
eval "$(export -p | sed "s/^export /report /;
                         s/^declare -x /report /;
                         s/typeset -x /report /")"

Обратите внимание, что в зависимости от оболочки export -pможет отображаться или не отображаться переменная, имя которой недопустимо в оболочке, а если нет, то она может указывать или не указывать имена должным образом. Например, переменные dash, mksh и zsh опускают переменные, имя которых включает символ новой строки, BusyBox dash и ksh93 печатают их в необработанном виде, а bash печатает их в необработанном виде без их значения. Если вам нужно защитить от ненадежного ввода, не полагайтесь на чисто POSIX-решение и определенно не вызывайте evalничего, полученного из вывода export -p.

Жиль "ТАК - перестань быть злым"
источник
Я не уверен, насколько «легко» это происходит с sed (1) с многострочными значениями - я бы хотел это увидеть. Но спасибо за метод awk (1). Я думаю, что это самый портативный способ (хотя я не думаю, что exitэто необходимо).
Хуан,
Обратите внимание, что если вы получите FOO<newline>BAR, вы не знаете, будет ли это FOO<newline>BARпеременная окружения (которая export -pне будет отображаться в большинстве оболочек, см. env $'FOO\nBAR=test' awk 'BEGIN{for (v in ENVIRON) print v}') Или FOOи BARпеременная окружения, и переменная окружения.
Стефан Шазелас
Обратите внимание, что GNU awks устанавливает собственные переменные окружения ( AWKPATHи AWKLIBPATHв моей системе)
Стефан Шазелас,
@ StéphaneChazelas - re: встроенная новая строка в var name - согласовано - трудно защититься от этого с помощью шелл-кода. Re: AWKPATH & AWKLIBPATH загрязнение, я заметил, что коварная вставка тоже. Это GNU AWK, а не BSD AWK.
Хуан,
0

Мне нравятся простые вещи; это будет работать для систем POSIX:

printenv | sed 's;=.*;;' | sort
HOME
HOSTNAME
PATH
PWD
SHLVL
TERM
todd_dsm
источник
5
export AAA=$'multi\nBBB=line'
Ройма
@todd_dsm - это не работает для переменных среды, значения которых охватывают более одной строки (например, иногда TERMCAP - я вижу это, когда на сессии screen (1), IIRC). Таким образом, этот ответ не соответствует требованиям, описанным в исходном вопросе. Мне также нравится простой, но это не работает в целом.
Хуан
Лакомые вы редактировали в исходном сообщении было интересно Баш: compgen -e. Это не помогает для моего переносимого скриптинга (например, когда bash недоступен), но это интересно.
Хуан
просто любопытно, зачем ограничивать себя оболочкой bourne (posix)? совместимость с posix - это здорово, но при этом вы теряете много функциональности. вы можете быть переносимым и НЕ посликсным с bash; это часть семьи GNU.
todd_dsm
Используя dashв Debian, я получаю те же результаты с помощью команды выше или, модифицированной printenv | sed 's;*=.;;' | sortдля получения значений. Я экспортировал переменную yoи назначил ей ваш первый комментарий выше; он напечатан, как и ожидалось, с несколькими строками. не уверен, что вы испытываете, но не должно быть усеченного вывода. запустить команду в оболочке; что бы он ни выводил, он должен работать; не ожидайте усечения. Затем в контексте TERMCAP / screen / iirc; должно быть таким же. Если выходные данные не совпадают, то это, вероятно, проблема с одной из этих программ.
todd_dsm