awk 스크립트에서 쉘 변수를 어떻게 사용합니까?


290

외부 셸 변수를 awk스크립트 에 전달하는 몇 가지 방법을 찾았 지만 '및 에 대해 혼란 스럽습니다 ".

먼저 쉘 스크립트를 사용해 보았습니다.

$ v=123test
$ echo $v
123test
$ echo "$v"
123test

그런 다음 awk를 시도했습니다.

$ awk 'BEGIN{print "'$v'"}'
$ 123test
$ awk 'BEGIN{print '"$v"'}'
$ 123

왜 차이점이 있습니까?

마지막으로 나는 이것을 시도했다 :

$ awk 'BEGIN{print " '$v' "}'
$  123test
$ awk 'BEGIN{print ' "$v" '}'
awk: cmd. line:1: BEGIN{print
awk: cmd. line:1:             ^ unexpected newline or end of string 

나는 이것에 대해 혼란스러워한다.


2
아래에 표시된 것처럼 -v가 마음에 들지만 실제로 쉘에서 물건을 보호하는 방법에 대해 생각할 때 훌륭한 연습입니다. 이를 통해 첫 번째 컷은 공백과 달러 기호에 백 슬래시를 사용합니다. 말할 필요도없이 여기의 예는 제 시간에 가치가있었습니다.
Chris


awk 검색에 정규 표현식이 필요한 경우을 넣을 수 없습니다 /var/. 대신 물결표를 사용하십시오.awk -v var="$var" '$0 ~ var'
Noam Manos

답변:


496

쉘 변수 가져 오기 awk

여러 가지 방법으로 수행 될 수 있습니다. 일부는 다른 것보다 낫습니다. 이것은 대부분을 다루어야합니다. 의견이 있으시면 아래에 남겨주세요. v1.5


사용 -v (가장 좋은 방법은, 대부분의 휴대용)

사용 -v옵션 : (PS는 뒤에 공백을 사용합니다 -v. 또는 덜 휴대용 될 것입니다 예, awk -v var=없습니다 awk -vvar=)

variable="line one\nline two"
awk -v var="$variable" 'BEGIN {print var}'
line one
line two

이것은 most와 호환 가능해야하며 awk변수는 BEGIN블록에서도 사용할 수 있습니다.

여러 변수가있는 경우 :

awk -v a="$var1" -v b="$var2" 'BEGIN {print a,b}'

경고 . 에드 모튼이 글을, 이스케이프 시퀀스는 이렇게 해석됩니다 \t진짜가된다 tab가 아니라 \t그게 당신이 검색 것입니다 경우. ENVIRON[]통해 사용 하거나 액세스 하여 해결할 수 있습니다ARGV[]

추신 : 세 개의 세로 막대를 구분 기호로 |||사용하려면 탈출 할 수 없으므로 사용하십시오.-F"[|][|][|]"

프로그램 / 함수 숙소에서 데이터를 가져 오는 예제 awk(여기서는 날짜가 사용됨)

awk -v time="$(date +"%F %H:%M" -d '-1 minute')" 'BEGIN {print time}'

코드 블록 후 변수

awk코드 다음에 변수를 얻습니다 . BEGIN블록에 변수가 필요하지 않으면 제대로 작동합니다 .

variable="line one\nline two"
echo "input data" | awk '{print var}' var="${variable}"
or
awk '{print var}' var="${variable}" file
  • 여러 변수 추가하기 :

awk '{print a,b,$0}' a="$var1" b="$var2" file

  • 이러한 방식으로 FS각 파일마다 다른 필드 구분 기호 를 설정할 수도 있습니다.

awk 'some code' FS=',' file1.txt FS=';' file2.ext

  • 코드 블록 뒤의 변수는 BEGIN블록에 대해 작동하지 않습니다 .

echo "input data" | awk 'BEGIN {print var}' var="${variable}"


여기 끈

변수 를 지원하는 쉘 awkhere-string 을 사용하여 변수를 추가 할 수도 있습니다 (Bash 포함).

awk '{print $0}' <<< "$variable"
test

이것은 다음과 같습니다.

printf '%s' "$variable" | awk '{print $0}'

PS 변수를 파일 입력으로 취급합니다.


ENVIRON 입력

TrueY가 쓰는 것처럼 환경 변수ENVIRON 를 인쇄 하는 데 사용할 수 있습니다 . AWK를 실행하기 전에 변수를 설정하면 다음과 같이 인쇄 할 수 있습니다.

X=MyVar
awk 'BEGIN{print ENVIRON["X"],ENVIRON["SHELL"]}'
MyVar /bin/bash

ARGV 입력

스티븐 페니 (Steven Penny)는 다음과 ARGV같이 데이터를 엉망으로 만들 수 있습니다 .

v="my data"
awk 'BEGIN {print ARGV[1]}' "$v"
my data

BEGIN뿐만 아니라 코드 자체로 데이터를 가져 오려면 :

v="my data"
echo "test" | awk 'BEGIN{var=ARGV[1];ARGV[1]=""} {print var, $0}' "$v"
my data test

코드 내 변수 : USE WITH주의

awk코드 내에서 변수를 사용할 수는 있지만 지저분하고 읽기 어려우며 Charles Duffy지적한 바와 같이이 버전은 코드 삽입의 희생자 일 수 있습니다. 누군가 변수에 나쁜 것을 추가하면 awk코드의 일부로 실행됩니다 .

이것은 코드 내에서 변수를 추출하여 작동하므로 일부가됩니다.

당신이 확인하려면 awk동적 변수를 사용하여 변경 것을, 당신은 이런 식으로 할 수 있지만 일반 변수를 사용하지 마십시오.

variable="line one\nline two"
awk 'BEGIN {print "'"$variable"'"}'
line one
line two

코드 삽입의 예는 다음과 같습니다.

variable='line one\nline two" ; for (i=1;i<=1000;++i) print i"'
awk 'BEGIN {print "'"$variable"'"}'
line one
line two
1
2
3
.
.
1000

awk이 방법으로 많은 명령을 추가 할 수 있습니다 . 유효하지 않은 명령으로도 충돌이 발생합니다.


추가 정보 :

큰 따옴표 사용

변수를 큰 따옴표로 묶는 것이 좋습니다. "$variable"
그렇지 않으면 여러 줄이 긴 단일 줄로 추가됩니다.

예:

var="Line one
This is line two"

echo $var
Line one This is line two

echo "$var"
Line one
This is line two

큰 따옴표없이 얻을 수있는 다른 오류 :

variable="line one\nline two"
awk -v var=$variable 'BEGIN {print var}'
awk: cmd. line:1: one\nline
awk: cmd. line:1:    ^ backslash not last character on line
awk: cmd. line:1: one\nline
awk: cmd. line:1:    ^ syntax error

작은 따옴표로 변수의 값을 확장하지 않습니다.

awk -v var='$variable' 'BEGIN {print var}'
$variable

AWK 및 변수에 대한 추가 정보

이 FAQ를 읽으십시오 .


2
"지저분하고 읽기 어려운"은 문자열을 awk 코드로 직접 대체 할 때 코드 삽입의 더 중요한 보안 문제를 무시합니다.
Charles Duffy

위의 답변을 읽으면 오류없이 스크립트를 실행할 수는 있지만 작업을 수행하지는 않습니다. awk -v repo = "$ 1"-v tag = "$ 2" '{sub (/ image : registryabx.azurecr.io \ / { 인쇄 저장소} : ([a-z0-9] +) $ /, "이미지 : registryabc.azurecr. io / {print repo} : {print tag}");} 1 './services/appscompose.yaml >> newcompose.yaml. 중첩 된 괄호 {
Darion Badlydone

@DarionBadlydone 이것을 시도하십시오 awk -v repo="$1" -v tag="$2" 'BEGIN {print "repo="repo,"tag="tag}'. 변수를 인쇄하는지 확인합니다. 알아낼 수없는 경우 자체 질문을 게시하십시오.
Jotne

@Jotne 예, 값을 인쇄하므로 다음과 같이 시도했습니다. awk -v repo = "$ 1"-v tag = "$ 2" '{print "{sub (/ image : registryabc.azurecr.io/"repo":( [a-z0-9] +) $ /, \ "image : registryabc.azurecr.io/"repo":"tag"\");}1"} './services/appscompose.yaml >> newcompose.yaml 그러나 측면에서 작동하지 않습니다. 소스 파일의 각 줄을 인쇄 된 명령으로 대체합니다
Darion Badlydone

@Jotne 어쨌든 감사합니다, 나오지도 함께했다
Darion Badlydone을

28

좋은 노인 인 것 같습니다 ENVIRON 내장 해시는 전혀 언급되지 않았습니다. 사용법의 예 :

$ X=Solaris awk 'BEGIN{print ENVIRON["X"], ENVIRON["TERM"]}'
Solaris rxvt

4
데이터를 그대로 전달하기 때문에 좋은 제안입니다. -v값에 백 슬래시가 포함되어 있으면 작동하지 않습니다.
그 다른 사람

2
@ thatotherguy 나는 그것을 몰랐다! 나는 awk -v x='\c\d' ...그것을 사용하면 제대로 사용될 것이라고 생각 했습니다. 그러나 awkx 가 인쇄 되면 유명한 메시지가 사라 집니다 : awk: warning: escape sequence '\c' treated as plain 'c'오류 메시지 ... 감사합니다!
TrueY

올바르게 작동합니다.이 문맥에서 올바르게 이스케이프 시퀀스를 확장하는 -v것이 의미 합니다. 그래서 \t변수에서 사용할 수 있고 데이터의 리터럴 탭과 일치 하도록 작동하도록 설계되었습니다 . 그게 당신이 다음 원하는 행동이 아니라면 당신은 사용하지 않는 -v사용 ARGV[]하거나 ENVIRON[].
Ed Morton

9

처리되는 셸 변수에서 백 슬래시를 원하는 방식에 따라 다음 중 하나를 사용하십시오 ( avarawk 변수, svar셸 변수).

awk -v avar="$svar" '... avar ...' file
awk 'BEGIN{avar=ARGV[1];ARGV[1]=""}... avar ...' "$svar" file

자세한 내용 및 기타 옵션 은 http://cfajohnson.com/shell/cus-faq-2.html#Q24 를 참조 하십시오 . 위의 첫 번째 방법은 거의 항상 최선의 선택이며 가장 명확한 의미가 있습니다.


6

변수 이름 ( )과 환경 변수 ( ) 의 값 ( )을 사용하여 명령 행 옵션 -v 을 전달할 수 있습니다 .v="${v}"

% awk -vv="${v}" 'BEGIN { print v }'
123test

또는 더 명확하게하기 위해 ( vs 가 훨씬 적음 ) :

% environment_variable=123test
% awk -vawk_variable="${environment_variable}" 'BEGIN { print awk_variable }'
123test

3

ARGV를 활용할 수 있습니다 :

v=123test
awk 'BEGIN {print ARGV[1]}' "$v"

몸에 계속 들어가려면 ARGC를 조정해야합니다.

awk 'BEGIN {ARGC--} {print ARGV[2], $0}' file "$v"

1

방금 "for loop"에 대한 @Jotne의 대답을 변경했습니다.

for i in `seq 11 20`; do host myserver-$i | awk -v i="$i" '{print "myserver-"i" " $4}'; done

1
이것은 -v기존의 많은 답변에서 이미 언급 한 Awk의 옵션 을 사용하는 방법에 대한 또 다른 예일뿐입니다 . 루프에서 Awk를 실행하는 방법을 보여주고 싶다면 실제로 다른 질문입니다.
tripleee

0

로그 파일의 줄 시작 부분에 날짜를 삽입해야했으며 다음과 같이 완료되었습니다.

DATE=$(date +"%Y-%m-%d")
awk '{ print "'"$DATE"'", $0; }' /path_to_log_file/log_file.log

저장하기 위해 다른 파일로 리디렉션 할 수 있습니다


큰 따옴표-작은 따옴표-큰 따옴표는 내가 광산을 작동시키는 데 정확히 필요한 것입니다.
user53029

2
이것은 코드 삽입 취약점으로 인해 사용해서는 안되는 방법으로 이미 받아 들여진 답변에 언급되었습니다. 따라서 여기의 정보는 중복되며 (허용 된 답변에 이미 설명되어 있음) 불완전합니다 (이 방법의 문제점은 언급하지 않음).
Jason S
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.