본문 바로가기

별걸다하는 IT/리눅스 유닉스

[리눅스 /유닉스 / 셸 스크립트] 매개변수 확장, 기타변수, 매개변수 치환 (Parameter substitution)

[Linux / Unix / Shell programming 완전 정복 목차]

안녕하세요~~

오늘은 변수편에 이어서 변수들을 손쉽게 조작하고 확장시키는데 사용되는 '매개변수 확장'에 대해서 다뤄볼게요~

 

혹 그전 포스팅을 보고오지 않으셨다면 참고하세요~

▶기본 변수 특징과 종류

 

[linux/unix/스크립트]셸 프로그래밍 기초 - 변수와 특수문자,빈 변수, 변수의 종류~ 변수총정리

[유닉스, 리눅스 셸 스크립트 프로그래밍 목차] 코딩을 항상 배우면 가장 먼저 배우게 되는 변수~~~ 오늘도 어김없이 찾아오는 변수편입니다. ㅎㅎ 변수란?! <--- 변수라는 단어가 뭘 의미하는지를 정리해놓은 완..

jhnyang.tistory.com

▶위치매개변수, 특수매개변수, 아규먼트 변수 등

불러오는 중입니다...

 

매개변수 확장 (Parameter Expansion)

$는 매개변수 확장, 산술 확장, 그리고 치환 등을 위해서 사용되는 변수관련 문자죠 ㅎㅎ.

셸마다 다르긴 하지만 많은 셸들이 확장과 치환등을 위한 다양한 방법들을 지원하고 있는데

어떤 것들이 있고, 어떻게 사용하는지 알아보도록 합시다.

 

먼저 헷갈릴때마다 참고하시라고 표로 정리해봤어요 ㅎㅎ

각각의 쓰임 방법과 헷갈릴 수 있는 부문에 대해서는 하단에 좀 더 자세히 기술했습니다 ~~ :)

종류

설명

${name}

name이라는 변수에 들어있는 값으로 치환한다. 변수명 다음에 다른 문자가 연이어 나올 경우 유용하다.

${#name}

name의 문자열 길이를 반환합니다.

name이 배열일 경우, 배열의 첫 번째 요소의 길이를 알려줍니다.

${#array[*]}

이렇게 하면 배열 요소의 개수를 반환합니다.

${#array[@]}

위와 동일한 역할을 수행!

${name:offset}

offset 다음부터 문자열을 추출합니다.

(name값에서 offset만큼 삭제한 후에 값을 반환한다)

${name:offset:length}

offset 다음부터 특정 길이만큼의 문자열을 추출합니다.

(name값에서 offset만큼 삭제한 후에 length만큼 센 뒤 값을 반환한다)

${name:=value}

name이 null이면 value로 할당하여 저장하고, name에 값이 있으면 그 값을 사용합니다. 변수의 기본값을 지정할 때 유용하다.

${name=value}

위와 같으나 널일 경우 적용되지 않는다. 변수 미선언시에 위와 동일하게 동작합니다.

${name:+value}

기존의 name이 null이 아니라면 value를 사용하지만 (즉 name이 값이 있다면 value 사용), name에 저장하지는 않습니다.

${name+value}

위와 같으나 널일 경우 적용되지 않는다. 변수 미선언시에 위와 동일하게 동작합니다.

${name:-value}

name에 값이 없으면 value값을 대입하고, 기존 name값이 있다면 그 값을 사용합니다. name에 value값을 저장하지는 않습니다.

${name-value}

위와 같으나 널일 경우 적용되지 않는다. 변수 미선언시에 위와 동일하게 동작합니다.

${name:?value}

기존에 name값이 있다면 기본값으로 하고, 값이 없으면 error를 내면서 value값을 보여줍니다.

${name?value}

위와 같으나 널일 경우 적용되지 않는다. 변수 미선언시에 위와 동일하게 동작합니다.

${name#substr}

name의 앞부분에서 가장 짧게 일치하는 $substr을 삭제합니다.

${name##substr}

name의 앞부분에서부터 가장 길게 일치하는 $substr을 삭제합니다.

${name%substr}

name의 뒷부분에서 가장 짧게 일치하는 substr을 삭제합니다.

${name%%substr}

name의 뒷부분에서 가장 길게 일치하는 $substr을 삭제합니다.

${name/찾는단어/변경단어}

처음 일치한 단어를 변경단어로 변경합니다.

${name//찾는단어/변경단어}

찾는단어와 일치하는 모든 단어를 변경단어로 변경합니다.

${name#찾는단어/변경단어}

name의 앞부분이 찾는단어와 일치하면 변경단어로 변경합니다.

${name%찾는단어/변경단어}

name의 뒷부분이 찾는단어와 일치하면 변경단어로 변경합니다.

${!name*}

${!name@}

선언된 변수 중에서 단어가 포함된 변수명을 추출합니다.

${name^^}

name 문자열을 모두 대문자로 바꿔줌!

만약 ^가 하나라면 첫문자만 바꿔줍니다.

${name,,}

name 문자열을 모두 소문자로 변경!

마찬가지로 컴마가 하나뿐이라면 첫 문자만 변경해줍니다.

요렇게 있습니다. 많아보이지만 규칙이 있어서 별거 읍어용~

${name}이 유용하게 쓰일 때~

문자열을 뭔가 덧붙여서 정의하고 싶을 때 $name을 사용하면 경계가 명확해해재지 않을 수 있어요 ㅎㅎ

예를 들어 $name20190819하면 변수 이름이 name까지인지 name20190819까지인지 알수가 없지만 ${name}20190819는 아 문자열이 저장된 변수가 확실히 name까지이구나 구분지을 수 있죠~

즉 문자열 변수들을 연결할 때 주로 사용됩니다.

FILE=dump 
echo ${FILE}.$(date +%Y%m%d).log

${#name}

'문자열길이 반환 & 배열 첫 요소 길이 반환 & 배열 전체 요소 개수 반환' 비교를 통해 확인하자

array=( first second third fourth ) #배열의 원소 개수는 4개이다 
str=hello 
echo \${#str} ${#str} echo \${#array} ${#array} 
echo \${#array[0]} ${#array[0]} 
echo \${#array[1]} ${#array[1]} 
echo \${#array[*]} ${#array[*]}

test.sh 스크립트를 위 코드처럼 짜주었습니다. 

결과창

결과를 보면, #str은 hello의 문자개수인 5를 출력하였고, 배열일 경우, 배열의 원소 개수가 아닌 첫 원소의 글자수를 출력한 것을 확인할 수 있습니다. 따라서 array[0]의 문자개수와 출력이 동일합니다.

#array[*]를 해주었을 경우, 배열이 전체 원소 개수를 출력하는 것 또한 확인할 수 있습니다.

 

문자열추출

IBM의 AIX의 ksh 셸에서는 문자열 추출 방식이 먹히지 않습니다. 

근데 우분투 bash에서는 잘됨. 즉 셸 인터프립터마다 다를 수 있다는 점~

${name:+value}랑 ${name:-value}랑 차이점

플러스와 마이너스는 서로 반대잖아요~ 얘네 역할도 반대예요

플러스는 name 값이 없으면 그대로~ 있으면 바꾸는거

마이너스는 있는거 그대로 쓰고, 만약 없으면 value로 바꾸는거

 

나만의 암기법?

저는 '-0+'이렇게 암기했어요~

마이너스는 왼쪽이니까 0보다 작을 경우(즉 없을 경우) 바꾸고, 플러스는 오른쪽이니까 값이 있을 때 치환!

 

그냥 단순 확인 예제 코드

echo plus example 
echo when str is not null plus changes value 
str=hello 
echo result: ${str:+change} 
echo str :${str} 
str= 
echo now str is null 
echo result: ${str:+change} 
echo str :${str}

결과창

결과는 change로 출력되었는데 str은 기존 hello로 출력된 것으로 본래 변수에다가 치환된 값을 저장하지 않는 것을 볼 수 있습니다. (:-또한 마찬가지로 동작합니다)

 

${name:-value}랑 ${name-value}랑 차이점?

마찬가지로 ${name:=value}랑 ${name=value} 차이 또한 같다.

그냥 콜론이 없는거랑 있는거랑 차이점이라 생각하면 된당.

str1= #set은 했지만 값은 null! 
echo str1=${str1-hello} 
echo str1 :${str1} 
echo str1=${str1:-hello2} 
echo str1 :${str1}

 

':이 있을 때는 매개변수가 선언만 되어 값이 널일 경우에도 기본값을 적용시킵니다.'

str1은 지금 선언 됐는데 초기화가 안된 상태입니다.

이럴 때 콜론(:)이 없는 -를 사용하게 되면 값이 없는데도 불구하고 'hello'로 치환되지 않아요!!

반면에 콜론이 있으면 초기화가 안된 상태여도 값을 치환해줘요 ㅎㅎ

 

${name:=value}랑 ${name:-value}랑 차이점

=는 대입, 값 할당 이라는 의미가 있잖아요

-나 + 요 아이들은, null이거나 unset일때, value를 반환해주는게 끝이고 name을 건드리지는 않아요

근데 =일 경우, null이거나 unset일 때 value를 name에다가 대입하는 과정을 거치기 때문에 반환뿐만 아니라 name또한 value로 변경되게 됩니다.

str= 
echo str :$str 
echo str-hello :${str:-hello} 
echo str :$str 
echo str:=heyy :${str:=heyy} 
echo str :$str

 

결과창

보면 '-'로 치환하고 str을 출력해보면 아무것도 출력되지 않는데!!

'='를 사용했을 때에는 str이 null이 아니라 'heyy'로 바뀐것을 확인할 수 있습니다.

 

위치매개변수와 쓸 경우 FAIL 되는 경우

조심해야할건, :=의 경우 위치매개변수와 함께 사용될 수 없어요~

인자값으로 아무것도 안넘겨줘서 null이면 hello로 값이 치환되어야 할 것 같은데 

cannot assign in this way라고 출력하면서 에러가 뜹니다

 

${name:?value}

?를 사용했을 경우 이렇게 value에 해당하는 값을 출력해줍니다~

${name:? ERROR: name is not defined}

 

이런 특징을 이용해서 위와 같은 방법으로 출력해서 사용할 수도 있겠죠?ㅎㅎ

 

특정 문자열 제거하는 REMOVE 패턴 예시

압축파일이여서 뒤에 tar.gz가 붙는 파일이 있다고 합시다. 그런데 뒤에 tar.gz는 빼고 파일명만 필요할 경우가 있어요 

file=backup20190801.tar.gz 
fname=${file%.tar.gz} 
echo $fname

 

이렇게 하면 '.tar.gz'를 제외한 backup20190801이 추출되겠죠?

 

또는 경로에서 디렉터리 path를 다 없애고 싶을 때~

한 예로 이 포스팅의 주소는 "/blog.naver.com/jhnyang/221621915301"인데 뒤의 포스팅넘버만 남기고 싶다~

url=/blog.naver.com/jhnyang/221621915301 
echo "${url##*/}"

이런식으로 때에 맞게 유용하게 사용될 수 있어요 ㅎㅎ

 

소문자 대문자 변경하는 '^^' ',,' 예시

lower=hello #소문자가 대문자로 다 변경되는지 확인을 위해 소문자변수를 하나 만들어주고 
upper=THANKS #대문자 변수도 하나 맹글어준당~ 
echo \${lower} ${lower} #비교를 위한 기존 소문자 문자열 출력~ 
echo \${lower^^} ${lower^^} # 대문자로 변경~ 
echo \${upper} ${upper} #비교를 위한 기존 대문자 문자열 출력~ 
echo \${upper\,\,} ${upper,,} #컴마를 출력해주기 위해 컴마 앞에 역슬래시 넣은거~ 소문자로 변경!

결과창!

잘 변경되었죵?ㅎㅎ

 

오늘은 기타변수라 불리기도 하고 확장매개변수라 불리기도 하고 매개변수 치환이라고 불리기도 하는 ~~~

다양한 표현법에 대해서 알아봤습니다 ㅎㅎ

시간이 벌써 이렇게 되었네요 다음 포스팅에서 또 봐요~~~

공감 또는 광고보답 또는 댓글 등은 정보공유의 사소한 행복을 전달해줍니다