bash에서 스크립트에 선언 된 변수를 나열하는 방법은 무엇입니까?


98

bash의 내 스크립트에는 많은 변수가 있으며 파일에 저장할 무언가를 만들어야합니다. 내 질문은 내 스크립트에 선언 된 모든 변수를 나열하고 다음과 같은 목록을 얻는 방법입니다.

VARIABLE1=abc
VARIABLE2=def
VARIABLE3=ghi

답변:


151

set 변수를 출력하지만 불행히도 함수 정의도 출력합니다.

다행히 POSIX 모드는 변수 만 출력합니다.

( set -o posix ; set ) | less

로 파이핑 less하거나 옵션을 원하는 위치로 리디렉션합니다.

따라서 스크립트에서 선언 된 변수를 얻으려면 :

( set -o posix ; set ) >/tmp/variables.before
source script
( set -o posix ; set ) >/tmp/variables.after
diff /tmp/variables.before /tmp/variables.after
rm /tmp/variables.before /tmp/variables.after

(또는 적어도 그것을 기반으로 한 것 :-))


내가 게시하는 동안 편집했습니다. -o posix이제 diff를 사용한 멋진 호출 에는 변수 만 포함됩니다.
ezpz

8
임시 파일을 사용하지 않고 : VARS="`set -o posix ; set`"; source script; SCRIPT_VARS="`grep -vFe "$VARS" <<<"$(set -o posix ; set)" | grep -v ^VARS=`"; unset VARS;. 그러면 바로 저장할 수있는 형식으로 변수도 출력됩니다. 목록이 변경 스크립트 (이것은이 바람직하다 여부 따라 다름)이라는 변수를 포함합니다
ivan_pozdeev가

1
@ErikAronesty를 사용하여 환경을 다시 만들 source수 있도록하려면 declare -p.
6

2
임시 파일을 사용하지 않고 diff (또는 유사한 명령)를 사용하여 전후 환경을 비교하려면 다음과 같이 할 수 있습니다.before=$(set -o posix; set); dosomestuff; diff <(echo "$before") <(set -o posix; set)
Six

1
@Caesar 아니요, 비어 있지 않은 배열 만 시도했습니다. 빈 배열의 경우 귀하가 옳습니다 – 그들은 인쇄되지 않습니다.
Socowi


10
for i in _ {a..z} {A..Z}; do eval "echo \${!$i@}" ; done | xargs printf "%s\n"

모든 쉘 변수 이름을 인쇄해야합니다. 어떤 변수가 새로운 것인지 비교하기 위해 "set"을 사용하는 것처럼 파일을 소싱하기 전후에 목록을 얻을 수 있습니다 (다른 답변에서 설명 됨). 그러나 diff를 사용한 이러한 필터링은 필요하지만 파일을 소싱하기 전에 존재했던 일부 변수를 필터링 할 수 있음을 명심하십시오.

귀하의 경우 변수 이름이 "VARIABLE"로 시작하는 것을 알고 있다면 스크립트를 소싱하고 다음을 수행 할 수 있습니다.

for var in ${!VARIABLE@}; do
   printf "%s%q\n" "$var=" "${!var}"
done

업데이트 : 순수 BASH 솔루션의 경우 (외부 명령이 사용되지 않음) :

for i in _ {a..z} {A..Z}; do
   for var in `eval echo "\\${!$i@}"`; do
      echo $var
      # you can test if $var matches some criteria and put it in the file or ignore
   done 
done

1
+1 및 oneliner 버전 (단일 평가 포함) :eval "printf '%q\n' $(printf ' "${!%s@}"' _ {a..z} {A..Z})"
netj

4

위의 답변 중 일부를 바탕으로 이것은 나를 위해 일했습니다.

before=$(set -o posix; set | sort);

소스 파일 :

comm -13 <(printf %s "$before") <(set -o posix; set | sort | uniq) 

3

후 처리를 할 수 있다면 (이미 언급했듯이) set스크립트의 시작과 끝에 (각각 다른 파일에 대해) 호출하고 두 파일에 대해 diff를 수행 할 수 있습니다. 여기에는 여전히 약간의 소음이 포함되어 있음을 인식하십시오.

프로그래밍 방식으로도 수행 할 수 있습니다. 출력을 현재 범위로만 제한하려면 변수 생성에 대한 래퍼를 구현해야합니다. 예를 들면

store() {
    export ${1}="${*:2}"
    [[ ${STORED} =~ "(^| )${1}($| )" ]] || STORED="${STORED} ${1}"
}

store VAR1 abc
store VAR2 bcd
store VAR3 cde

for i in ${STORED}; do
    echo "${i}=${!i}"
done

어느 양보

VAR1=abc
VAR2=bcd
VAR3=cde

2

다음은 @GinkgoFr 답변과 비슷하지만 @Tino 또는 @DejayClayton으로 식별되는 문제가 없으며 @DouglasLeeder의 영리한 set -o posix비트 보다 더 강력합니다 .

+ function SOLUTION() { (set +o posix; set) | sed -ne '/^\w\+=/!q; p;'; }

차이점은이 솔루션이 첫 번째 비 변수 보고서 (예 : set

BTW : "티노"문제가 해결되었습니다. POSIX가 꺼져 있고 함수가에 의해보고 되더라도 솔루션 setsed ...일부는 (예 : VAR=VALUE줄)을 통한 변수 보고서 만 허용합니다 . 특히 A2는 가짜로 출력으로 만들지 않습니다 .

+ function a() { echo $'\nA2=B'; }; A0=000; A9=999; 
+ SOLUTION | grep '^A[0-9]='
A0=000
A9=999

AND : "DejayClayton"문제가 해결되었습니다 (변수 값에 포함 된 줄 바꿈 은 출력을 방해 하지 않습니다VAR=VALUE .

+ A1=$'111\nA2=222'; A0=000; A9=999; 
+ SOLUTION | grep '^A[0-9]='
A0=000
A1=$'111\nA2=222'
A9=999

참고 : @DouglasLeeder에서 제공하는 솔루션은 "DejayClayton"문제 (새 줄이 포함 된 값)로 어려움을 겪습니다. 아래 A1는 잘못된 것이며 A2전혀 표시해서는 안됩니다.

$ A1=$'111\nA2=222'; A0=000; A9=999; (set -o posix; set) | grep '^A[0-9]='
A0=000
A1='111
A2=222'
A9=999

마지막으로 : bash문제 의 버전은 생각하지 않지만 그럴 수도 있습니다. 나는 이것을 테스트 / 개발했습니다.

$ bash --version
GNU bash, version 4.4.12(1)-release (x86_64-pc-msys)

POST-SCRIPT : OP에 대한 다른 응답 중 일부를 감안할 때 set 항상 값 내에서 줄 바꿈을으로 변환 하는 것이 100 % 미만임을 확신합니다. \n이 솔루션은 "DejayClayton"문제를 피하기 위해 의존합니다. 아마도 그것은 현대적인 행동일까요? 아니면 컴파일 시간 변형입니까? 또는 set -o또는 shopt옵션 설정? 이러한 변형 알고 있다면 의견을 추가하십시오 ...


0

스크립트를 사용해보십시오 ( "ls_vars"라고 부릅니다).

  #!/bin/bash
  set -a
  env > /tmp/a
  source $1
  env > /tmp/b
  diff /tmp/{a,b} | sed -ne 's/^> //p'

chmod + x it 및 :

  ls_vars your-script.sh > vars.files.save

0

보안 관점에서 @akostadinov의 대답 또는 @JuvenXu의 대답set다음과 같은 잠재적 인 보안 결함으로 인해 명령 의 구조화되지 않은 출력에 의존하는 것보다 낫습니다 .

#!/bin/bash

function doLogic()
{
    local COMMAND="${1}"
    if ( set -o posix; set | grep -q '^PS1=' )
    then
        echo 'Script is interactive'
    else
        echo 'Script is NOT interactive'
    fi
}

doLogic 'hello'   # Script is NOT interactive
doLogic $'\nPS1=' # Script is interactive

위의 함수 doLogic는 스크립트가 대화 형인지 여부를 결정하기 위해 set변수의 존재를 확인하는 데 사용 합니다 PS1(이게 목표를 달성하는 가장 좋은 방법인지 여부는 신경 쓰지 마십시오. 이것은 단지 예일뿐입니다).

그러나의 출력 set은 구조화되지 않았으므로 개행을 포함하는 모든 변수가 결과를 완전히 오염시킬 수 있습니다.

물론 이것은 잠재적 인 보안 위험입니다. 대신 간접 변수 이름 확장에 대한 Bash의 지원 또는 compgen -v.


0

이것을 시도하십시오 : set | egrep "^\w+="( | less배관 유무에 관계없이 )

첫 번째 제안 된 솔루션 ( set -o posix ; set ) | less인는 작동하지만 단점이 있습니다. 제어 코드를 단말기로 전송하여 제대로 표시되지 않는다는 것입니다. 이 경우에 따라서 예를 들어, (가능성이)IFS=$' \t\n' 변수, 우리는 볼 수 있습니다 :

IFS='
'

… 대신.

egrep솔루션은 이것을 (그리고 결국 다른 유사한 것들) 제대로 표시합니다.


당신도 알다시피, 팔년이었다
lauriys

명백한 잘못된 bash -c $'a() { echo "\nA=B"; }; unset A; set | egrep "^\w+="' | grep ^A 디스플레이 이기 때문에 반대 투표A=B" -> 실패!
Tino

"_"(이전 명령의 마지막 인수) 의사 변수 만 암시하는 것처럼 보이지만 다른 테스트, 특히 IFS에서는 실패하지 않는 이상한 테스트입니다. "bash -c"로 실행하면 중요하지 않을 수도 있습니다. 최소한 하향 표 대신 중립을 유지해야합니다.
GingkoFr

0

나는 아마 전에 대답 을 훔 쳤을 것입니다 ... 어쨌든 func와 약간 다릅니다.

    ##
    # usage source bin/nps-bash-util-funcs
    # doEchoVars
    doEchoVars(){

        # if the tmp dir does not exist
        test -z ${tmp_dir} && \
        export tmp_dir="$(cd "$(dirname $0)/../../.."; pwd)""/dat/log/.tmp.$$" && \
        mkdir -p "$tmp_dir" && \
        ( set -o posix ; set )| sort >"$tmp_dir/.vars.before"


        ( set -o posix ; set ) | sort >"$tmp_dir/.vars.after"
        cmd="$(comm -3 $tmp_dir/.vars.before $tmp_dir/.vars.after | perl -ne 's#\s+##g;print "\n $_ "' )"
        echo -e "$cmd"
    } 

0

printenv명령

printenvenvironment variables값과 함께 모두 인쇄 합니다.

행운을 빕니다...


0

이를 수행하는 간단한 방법은 스크립트를 실행하기 전에 시스템 환경 변수를 설정 하여 bash 엄격 모드 를 사용하고 diff를 사용하여 스크립트 중 하나만 정렬하는 것입니다.

# Add this line at the top of your script :
set > /tmp/old_vars.log

# Add this line at the end of your script :
set > /tmp/new_vars.log

# Alternatively you can remove unwanted variables with grep (e.g., passwords) :
set | grep -v "PASSWORD1=\|PASSWORD2=\|PASSWORD3=" > /tmp/new_vars.log

# Now you can compare to sort variables of your script :
diff /tmp/old_vars.log /tmp/new_vars.log | grep "^>" > /tmp/script_vars.log

이제 /tmp/script_vars.log에서 스크립트의 변수를 검색 할 수 있습니다. 아니면 적어도 그것을 기반으로 한 것!


0

파티에 조금 늦었지만 여기에 또 다른 제안이 있습니다.

#!/bin/bash

set_before=$( set -o posix; set | sed -e '/^_=*/d' )

# create/set some variables
VARIABLE1=a
VARIABLE2=b
VARIABLE3=c

set_after=$( set -o posix; unset set_before; set | sed -e '/^_=/d' )
diff  <(echo "$set_before") <(echo "$set_after") | sed -e 's/^> //' -e '/^[[:digit:]].*/d'

DIFF + 나오지 파이프 라인 명령 줄은 원하는 형식의 모든 스크립트 정의 변수를 (영업 이익의 게시물에 지정된대로)를 출력한다 :

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