bash에서 정의 된 변수 (쉘 및 / 또는 환경 변수) 만 인쇄하는 방법


57

bash builtin 명령 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
지금까지 최고의 솔루션
Ruslan

1
로 시작 _하기 쉬운 일반적으로 흥미없는 변수 가 많이 있습니다.(set -o posix ; set | grep -v ^_)
hyde

이것은 너무 오랫동안 나를 귀찮게했습니다! 여러 줄 값이 있으면 _로 시작하는 줄만으로는 충분하지 않지만 값의 내용은 그대로 유지됩니다. set은 행을 순서대로 인쇄하기 때문에 모든 _ 행이 끝에 있으므로 다음을 사용하여 첫 번째 _ 행 다음에 결과를 간단히 잘라낼 수 있습니다.set -o posix; set | sed -e '/^_/,$d'; set +o posix;
Scott

1
참고 사항 : 괄호는에서 중요 (set -o posix; set)합니다. 대괄호가 없으면 현재 Bash 쉘의 동작이 Posix 표준과 일치하도록 변경됩니다. (의미하지만 의미가있는 것은 아닙니다.) 대괄호를 사용하면 Bash는 변경되지 않습니다.
John Red

1
부작용 : 설정 POSIXLY_CORRECT=y및 추가 posix$SHELLOPTS
톰 헤일

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

다음을 사용하여 속성을 잘라낼 수 있습니다.

$ 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

bash 내장 compgen은 완성 스크립트에서 사용하기위한 것입니다. 이를 위해 compgen -v정의 된 모든 변수를 나열합니다. 단점 : 변수 이름 만 나열하고 값은 나열하지 않습니다.

다음은 값을 나열하는 해킹입니다.

$ compgen -v | while read var; do printf "%s=%q\n" "$var" "${!var}"; done

장점은 순수한 bash 솔루션입니다. 단점 :를 통한 해석으로 인해 일부 값이 엉망 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
Steven 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 -마지막으로, 우리는 파이프의 정렬 된 출력 envcomm와 사용 -23이 경우, 세트에서 우리의 출력에 고유 한 선을 첫 번째 인수에 고유 한 라인을 인쇄하는 옵션을 선택합니다.

완료되면 명령으로 작성한 임시 파일을 정리할 수 있습니다. rm ./setvars


명령의 문제는 이식성이 아닙니다 (물론 bash에만 국한되지만 grep 측에는 문제가 없습니다). 문제는 함수 정의에서 일부 줄을 잡고 있다는 것입니다. Bash는 대부분의 함수 코드를 들여 쓰지만 그중 일부는, 특히 여기 문서 내의 텍스트가 아닙니다 ( f () {|cat <<EOF|foo=bar|EOF|}여기서는 |줄 바꿈을 나타냄).
Gilles

6

그냥 명령을 사용하십시오 env. 기능을 인쇄하지 않습니다.


1
스크립트 내에서 사용되는 경우 수행됩니다.
DocSalvager

2

printenv 명령을 시도하십시오 :

$printenv

6
printenv 및 env는 내 보낸 (환경) 변수 만 인쇄하고 내 보내지 않은 (쉘) 변수는 인쇄하지 않습니다.
Lri

@Lri 감사합니다! 내 보낸 변수를 인쇄하는 방법이 궁금합니다.
마크 스튜어트

1

bash에서는 변수 이름 만 인쇄합니다.

compgen -v

또는 값이 필요한 경우 다음을 사용하십시오.

declare -p

당신의 노고에 감사드립니다. 난 이미 내 대답에 그 가능성을 언급 한 점에 유의하시기 바랍니다 unix.stackexchange.com/a/5691/1170 어쨌든 upvote에가 있습니다.
lesmana

0

rc 스크립트의 vars가 빠지지 않도록 깨끗한 ​​쉘과 비교

## 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 

두 함수 모두 첫 번째 함수가 나열 될 때 발생하는 '='문자가없는 줄을 찾을 때까지 줄을 덤프하여 작동합니다. 후자는 과제를 잘라냅니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.