Linux Bash 스크립트에서 eval을 사용하는 방법
게시 됨: 2022-08-22 모든 Bash 명령 중에서 가난한 old eval
이 아마도 가장 평판이 좋지 않을 것입니다. 정당화, 아니면 그냥 나쁜 언론? 우리는 가장 사랑받지 못하는 이 Linux 명령의 사용과 위험에 대해 논의합니다.
우리는 평가에 대해 이야기해야 합니다
부주의하게 사용되는 eval
은 예측할 수 없는 동작과 시스템 불안정으로 이어질 수 있습니다. 그 소리에서 우리는 아마 그것을 사용하지 말아야 할 것입니다. 그렇죠? 글쎄요.
자동차에 대해서도 비슷한 말을 할 수 있습니다. 잘못된 손에는 치명적인 무기입니다. 사람들은 ram-raid와 도주 차량에서 그들을 사용합니다. 우리 모두 자동차 사용을 중단해야 합니까? 물론 아닙니다. 그러나 그것들은 적절하게, 그리고 그것을 운전할 줄 아는 사람들에 의해 사용되어야 합니다.
eval
에 적용되는 일반적인 형용사는 "evil"입니다. 그러나 모든 것은 그것이 어떻게 사용되는지에 달려 있습니다. eval
명령은 하나 이상의 변수에서 값 을 대조합니다. 명령 문자열을 생성합니다. 그런 다음 해당 명령을 실행합니다. 이것은 스크립트를 실행하는 동안 명령의 내용이 동적으로 파생되는 상황에 대처해야 할 때 유용합니다.
스크립트 외부 에서 받은 문자열에 대해 eval
을 사용하도록 스크립트를 작성할 때 문제가 발생합니다. 사용자가 입력하거나 API를 통해 전송하거나 HTTPS 요청에 태그를 지정하거나 스크립트 외부의 다른 곳에서 입력할 수 있습니다.
eval
이 작동할 문자열이 로컬 및 프로그래밍 방식으로 파생되지 않은 경우 문자열에 포함된 악성 명령 또는 기타 잘못된 형식의 입력이 포함될 위험이 있습니다. 분명히 eval
이 악성 명령을 실행하는 것을 원하지 않습니다. 따라서 안전을 위해 외부에서 생성된 문자열이나 사용자 입력과 함께 eval
을 사용하지 마십시오.
평가의 첫 단계
eval
명령은 기본 제공 Bash 셸 명령입니다. Bash가 있는 경우 eval
이 있습니다.
eval
은 매개변수를 단일 문자열로 연결합니다. 연결된 요소를 분리하기 위해 단일 공백을 사용합니다. 인수를 평가한 다음 전체 문자열을 쉘에 전달하여 실행할 수 있습니다.
wordcount
라는 변수를 만들어 보겠습니다.
wordcount="wc -w raw-notes.md"
문자열 변수에는 "raw-notes.md"라는 파일의 단어 수를 세는 명령이 포함되어 있습니다.
eval
을 사용하여 변수 값 을 전달하여 해당 명령을 실행할 수 있습니다.
eval " $wordcount "
명령은 서브쉘이 아닌 현재 쉘에서 실행됩니다. 우리는 이것을 쉽게 보여줄 수 있습니다. "variables.txt"라는 짧은 텍스트 파일이 있습니다. 이 두 줄을 포함합니다.
첫 번째=방법 두 번째 = 괴짜
우리는 cat
을 사용하여 이 라인을 터미널 창으로 보낼 것입니다. 그런 다음 eval
을 사용하여 cat
명령을 평가하여 텍스트 파일 내의 지침이 실행되도록 합니다. 이것은 우리를 위해 변수를 설정할 것입니다.
고양이 변수.txt 평가 "$(고양이 변수.txt)" 에코 $첫 번째 $초
echo
를 사용하여 변수 값을 인쇄하면 eval
명령이 서브쉘이 아닌 현재 쉘에서 실행되는 것을 볼 수 있습니다.
서브쉘의 프로세스는 상위 쉘 환경을 변경할 수 없습니다. eval은 현재 셸에서 실행되기 때문에 eval
로 설정한 변수는 eval
명령을 실행한 셸에서 사용할 수 있습니다.
스크립트에서 eval
을 사용하는 경우 eval
에 의해 변경되는 셸은 스크립트를 시작한 셸이 아니라 스크립트가 실행 중인 하위 셸입니다.
관련: Linux cat 및 tac 명령을 사용하는 방법
명령 문자열에서 변수 사용
명령 문자열에 다른 변수를 포함할 수 있습니다. 정수를 담기 위해 두 개의 변수를 설정할 것입니다.
숫자1=10 숫자2=7
두 숫자의 합을 반환하는 expr
명령을 저장할 변수를 만듭니다. 이는 명령에서 두 정수 변수의 값에 액세스해야 함을 의미합니다. expr
문 주변의 백틱에 유의하십시오.
add="`expr $num1 + $num2`"
우리는 expr
문의 결과를 보여주는 또 다른 명령을 만들 것입니다.
show="에코"
echo
문자열의 끝이나 expr
문자열의 시작 부분에 공백을 포함할 필요가 없습니다. eval
이 처리합니다.
그리고 우리가 사용하는 전체 명령을 실행하기 위해:
평가 $show $add
expr
문자열 내의 변수 값은 실행할 셸에 전달되기 전에 eval
에 의해 문자열로 대체됩니다.
관련: Bash에서 변수로 작업하는 방법
변수 안의 변수 접근하기
변수에 값을 할당한 다음 해당 변수의 이름 을 다른 변수에 할당할 수 있습니다. eval
을 사용하면 두 번째 변수에 저장된 값인 이름에서 첫 번째 변수에 있는 값 에 액세스할 수 있습니다. 예를 들어보면 그 문제를 푸는 데 도움이 될 것입니다.
이 스크립트를 편집기에 복사하고 "assign.sh"라는 파일로 저장합니다.
#!/bin/bash title="긱 방법" 웹페이지=제목 명령="에코" 평가 $command \${$webpage}
chmod
명령으로 실행 가능하게 만들어야 합니다.
chmod +x assign.sh
이 문서에서 복사한 모든 스크립트에 대해 이 작업을 수행해야 합니다. 각각의 경우에 적절한 스크립트 이름을 사용하십시오.
스크립트를 실행할 때 eval
명령이 변수 webpage
를 사용하고 있음에도 불구하고 변수 title
의 텍스트를 봅니다.
./assign.sh
이스케이프 처리된 달러 기호 " $
"와 중괄호 " {}
"는 eval이 webpage
변수에 이름이 저장된 변수 내부에 있는 값을 보도록 합니다.
동적으로 생성된 변수 사용
eval
을 사용하여 변수를 동적으로 생성할 수 있습니다. 이 스크립트를 "loop.sh"라고 합니다.
#!/bin/bash 총=0 label="반복 완료. 총계:" {1..10}의 n에 대해 하다 평가 x$n=$n echo "루프" $x$n ((총+=$x$n)) 완료 에코 $x1 $x2 $x3 $x4 $x5 $x6 $x7 $x8 $x9 $x10 에코 $label $총계
그것은 우리가 생성한 변수의 값의 합을 보유하는 total
이라는 변수를 생성합니다. 그런 다음 label
이라는 문자열 변수를 만듭니다. 이것은 간단한 텍스트 문자열입니다.
우리는 10번 반복하고 x1
~ x10
이라는 10개의 변수를 만들 것입니다. 루프 본문의 eval
문은 "x"를 제공하고 루프 카운터 $n
의 값을 사용하여 변수 이름을 만듭니다. 동시에 새 변수를 루프 카운터 $n
값으로 설정합니다.
새 변수를 터미널 창에 인쇄한 다음 새 변수 값으로 total
변수를 증가시킵니다.
루프 외부에서 10개의 새 변수가 모두 한 줄에 다시 한 번 인쇄됩니다. 계산되거나 파생된 이름의 버전을 사용하지 않고 실제 이름으로도 변수를 참조할 수 있습니다.
마지막으로 total
변수의 값을 출력합니다.
./loop.sh
관련: 입문서: Bash 루프: for, while 및 until
배열과 함께 eval 사용하기
장기간 실행되고 일부 처리를 수행하는 스크립트가 있는 시나리오를 상상해 보십시오. 타임스탬프에서 생성된 이름으로 로그 파일에 기록합니다. 경우에 따라 새 로그 파일을 시작합니다. 스크립트가 완료되면 오류가 없으면 생성한 로그 파일을 삭제합니다.
단순히 rm *.log
를 원하지 않고 생성한 로그 파일만 삭제하기를 원합니다. 이 스크립트는 해당 기능을 시뮬레이션합니다. 이것은 "clear-logs.sh"입니다.
#!/bin/bash -a 로그 파일 선언 파일 수=0 rm_string="에코" 함수 create_logfile() { ((++파일 수)) 파일 이름=$(날짜 +"%Y-%m-%d_%H-%M-%S").log 로그 파일[$filecount]=$filename echo $filecount "생성됨" ${logfiles[$filecount]} } # 스크립트 본문. 여기에서 일부 처리가 수행됩니다. # 주기적으로 로그 파일을 생성합니다. 우리는 그것을 시뮬레이션 할 것입니다 create_logfile 수면 3 create_logfile 수면 3 create_logfile 수면 3 create_logfile # 제거할 파일이 있습니까? ((파일=1; 파일<=$filecount; 파일++)) 하다 # 로그 파일 제거 평가 $rm_string ${logfiles[$file]} "삭제됨..." 로그 파일[$file]="" 완료
스크립트는 logfiles
라는 배열을 선언합니다. 이것은 스크립트에 의해 생성된 로그 파일의 이름을 보유합니다. filecount
라는 변수를 선언합니다. 이것은 생성된 로그 파일의 수를 보유합니다.
또한 rm_string
이라는 문자열을 선언합니다. 실제 스크립트에서 여기에는 rm
명령이 포함되지만 비파괴 방식으로 원리를 시연할 수 있도록 echo
를 사용합니다.
create_logfile()
함수는 각 로그 파일의 이름이 지정되고 열리는 위치입니다. 우리는 단지 filename 을 생성하고 파일 시스템에서 생성된 것처럼 가장합니다.
이 함수는 filecount
변수를 증가시킵니다. 초기 값은 0이므로 생성한 첫 번째 파일 이름은 배열의 1번 위치에 저장됩니다. 이것은 의도적으로 수행되며 나중에 참조하십시오.
파일 이름은 date
명령과 ".log" 확장자를 사용하여 생성됩니다. 이름은 filecount
로 표시된 위치의 배열에 저장됩니다. 이름이 터미널 창에 인쇄됩니다. 실제 스크립트에서는 실제 파일도 생성합니다.
스크립트의 본문은 sleep
명령을 사용하여 시뮬레이션됩니다. 첫 번째 로그 파일을 만들고 3초를 기다린 다음 다른 로그 파일을 만듭니다. 파일 이름의 타임스탬프가 서로 다르도록 간격을 두고 4개의 로그 파일을 만듭니다.
마지막으로 로그 파일을 삭제하는 루프가 있습니다. 루프 카운터 파일은 1로 설정됩니다. 생성된 파일 수를 보유하는 filecount
값을 포함하여 계산됩니다.
로그 파일이 생성되지 않았기 때문에 filecount
가 여전히 0으로 설정되어 있으면 1이 0보다 작거나 같지 않기 때문에 루프 본문이 실행되지 않습니다. 이것이 filecount
변수가 선언될 때 0으로 설정되고 첫 번째 파일이 생성 되기 전에 증가된 이유입니다.
루프 내에서 비파괴적인 rm_string
및 배열에서 검색된 파일 이름과 함께 eval
을 사용합니다. 그런 다음 배열 요소를 빈 문자열로 설정합니다.
이것은 우리가 스크립트를 실행할 때 보게 되는 것입니다.
./clear-logs.sh
나쁜 것만은 아니다
악의적인 eval
는 확실히 용도가 있습니다. 대부분의 도구와 마찬가지로 무모하게 사용하면 위험하며 여러 면에서 위험합니다.
작동하는 문자열이 내부적으로 생성되고 사람, API 또는 HTTPS 요청과 같은 항목에서 캡처되지 않는지 확인하면 주요 함정을 피할 수 있습니다.
관련: Linux 터미널에서 날짜와 시간을 표시하는 방법(및 Bash 스크립트에서 사용)