shell 파라미터 치환

${ 파라미터 }

${Parameter}$Parameter와 같은 표현으로 주로 붙여쓴 경우에 구분을 위해서 사용하는 표기로 알려져 있다.

your_id=${USER}-on-${HOSTNAME}
echo "$your_id"
#
echo "Old \$PATH = $PATH" 
PATH=${PATH}:/opt/bin
echo "New \$PATH = $PATH"

${ 파라미터-디폴트}, ${파라미터:-디폴트}

파라미터가 정의되지 않았다면 디폴트값을 쓸 수 있게 해준다.

var1=1
var2=2
# var3 is not defined
echo ${var1-$var2} # 1
echo ${var3-$var2} # 2

echo ${username-`whoami`} # username이 정의되지 않았다면 `whoami`의 결과를 출력한다.

-, :- 의 차이는 별로 없다. 다만 - 는 변수이름자체가 정의되지 않았을 때 동작하며, :- 는 값이 null 일 때도 동작한다.

username0=     # null
# username1, username2 는 선언조차 되지 않음
echo ${username0-`whoami`} # 프린트 되지 않는다.
echo ${username1-`whoami`} # 프린트 된다.
echo ${username2-`whoami`} # 프린트 된다.

echo ${username0:-`whoami`} # 프린트 된다.
#               ^
echo ${username1:-`whoami`} # 프린트 된다.
echo ${username2:-`whoami`} # 프린트 된다.


이는 흔히 스크립트 내에서 인자가 생략되었을 경우 디폴트 값을 쓰는 데 쓰인다.

#!/usr/bin/bash
# add.sh
x=$((${1-1}+${2-2}))
echo $x

그리고 다음과 같이 쓴다.

$ add.sh 30 40
70
$ add.sh 30
32
$ add.sh
3

${파라미터=디폴트}, ${파라미터:=디폴트}

${-} 는 없는 변수에 대해 그 값만 디폴트를 취하는 것인데, 이 표현은 변수가 없거나 null 값이면 (:=의 경우) 즉석에서 해당 변수를 정의한다. 따라서 해당 문맥 이후에는 내부에서 정의한 변수값을 계속 사용할 수 있게 된다.

$ echo ${var=abc} # abc
$ echo ${var=xyz} # abc
$ echo $var # abc

${파라미터+대체값}, ${파라미터:+대체값}

잘 쓰이지는 않을 것 같은데 :-의 반대 표현이다. 선언되었고 값이 정의되어 있는 경우에만 대체값이 쓰인다. 그렇지 않은 경우 널스트링이다. :+의 경우에는 선언은되었으나 값이 널인 경우만 대체값을 쓴다.

${파라미터?에러메시지}, ${파라미터:?에러메시지}

파라미터가 있으면 그 값을 쓴다. 그렇지 않은 경우에는 에러메지시를 표시하고 리턴 코드 1을 내며 스크립트를 즉시 종료한다.

${#변수}

변수를 확장했을 때 문자의 길이가 된다. 배열인 경우에는 첫번째 원소의 길이가 된다.

$ x="hello world"
$ echo ${#x}
11
$ y=(hello world)
$ echo ${#y}
5 # hello

${변수#패턴}, \${변수##패턴}

변수를 확장한 값에 대해서 패턴과 매치되는 최소(#), 최대(##) 매칭을 제거한다.

# current directory
echo $PWD  # 전체 경로 출력
echo ${PWD##*/} # 디렉토리 이름만
filename=hello.txt
ext=${filename##*.} # txt

${변수%패턴}, ${변수%%패턴}

변수의 값에 대해서 패턴과 매치되는 맨 뒤쪽 끝 매칭을 제거한다. % 는 최소, %%는 최대이다.

var1=abcd12345abc6789
pattern1=a*c

echo
echo "var1 = $var1"
echo "var1 = ${var1}"

echo "Number of characters in ${var1} = ${#var1}"
echo

echo "pattern1 = $pattern1"
echo "----------------"
echo '${var1#$pattern1} =' "${var1#$pattern1}" # abcd12345abc6789
#                                         |-|
# d12345abc6789
echo '${var1##$pattern1} =' "${var1##$pattern1}" # abcd12345abc6789
#                                           |----------|
# 6789
echo;echo;echo

pattern2=b*9
echo "var1 = $var1"
echo
echo "pattern2 = $pattern2"
echo "--------------"
echo '${var1%$pattern2} = ' "${var1%$pattern2}" # abcd12345abc6789
#                                                        |----|
# abcd12345a
echo '${var1%%$pattern2} = ' "${var1%%$pattern2}"   # abcd12345abc6789
#                                              |-------------|
# a

다음은 이를 활용한 확장자 변경 스크립트 (이름만 바꾼다.)

#!/bin/bash

E_BADARGS=65

case $# in
  0|1)     # 인자의 개수가 0, 1개인 경우,
  echo "Usage: `basename $0` old_file_suffix new_file_suffix"
  exit $E_BADARGS
esac

for filename in *.$1
do
    mv $filename ${filename%$1}$2
done

exit 0

그외 몇 가지 더…

  • ${var:pos} : 주어진 위치부터 끝까지
  • ${var:pos:len} : 중간 슬라이스
  • ${var/pattern/replacement}: 패턴에 일치하는 부분을 치환한다.
  • ${var//pattern/replacement} : 패턴에 일치하는 부분 전체를 치환한다.
  • ${var/#pattern/replacement} : 패턴에 일치하는 부분을 맨 앞 한군데만 치환한다. (맨 첫 시작부터 매칭해야 함)
  • ${var/%pattern/replacement} : 패턴에 일치하는 부분을 맨 뒤 한군데만 치환한다. (맨 끝부분이 정확히 일치해야 함)
  • ${!varprefix*}, ${!varprefix@} : 변수이름이 접두사와 매칭하는 전체 변수값들을 가져온다.