[리눅스 기초] 쉘 스크립트의 사칙연산과 문자열 자르기

By | 2023-09-26

쉘 스크립트에서도 자바(Java)나 C언어처럼 문자열 자르기와 사칙연산을 비롯한 연산이 모두 가능하다. 아니 어쩌면 더 쉽게 느껴질 수도 있다. 하지만 이런 연산을 설명하기 전에 먼저 쉘 스크립트에서는 변수를 어떻게 사용하는지 이해해야 한다.

쉘 스크립트에서의 변수

일반적인 Java나 C와 같은 프로그래밍 언어에서는 변수의 선언과 타입(type)이 무척 중요하다. 선언하지 않고 사용하거나 잘못 참조하거나 잘못 연산하게 되면 엉뚱한 값이 출력되거나 컴파일 시 에러를 팍팍~뿌려댄다. 하지만 쉘스크립트에서 변수는 미리 선언하지 않아도 실행 시 자동으로 할당되며 타입을 지정하지 않고 사용해도 된다.

이따금씩 쉘 스크립트를 작성하다 보면 문자열과 숫자의 취급이 헷갈리곤 한다. C언어나  Java언어에서는 변수에 저장될 값이 숫자냐 문자냐를 무척 따져 형변환을 안해주게 되면 가차없이 컴파일 시 에러를 뿌려주는데 반해 쉘 스스크립트는 거침없이 알아서 연산을 하기 때문에 오히려 주의하지 않으면 아무런 에러도 발생하지 않고 엉뚱한 결과를 출력해줘서 오류를 찾기가 더 어려운 경우도 많다.

자 그럼 쉘 스크립트에서 가장 많이(?) 사용되는 대표적인 연산인 덧셈과 문자열을 붙여주는 연산을 통해 변수가 어떻게 사용되는지 알아보자. 아래의 두 연산을 보면 쉽게 이해할 수 있다.

1:   a=10        /* a 변수에 숫자 10  */
2:   b=10        /* b 변수에 숫자 10  */

3:   let c=a+b     /* 덧셈 연산  */

4:   echo $a+$b=$c      /* 결과 출력 :  10+10=20  */

5:   c=$a$b        /* 문자열 합치기 */

6:   echo $c         /* 결과 출력 : 1010   */

1행과 2행에서 변수 a와 b에 10이라는 숫자가 할당된 것으로 생각할 수 있지만 변수 a와 b는 할당되어 저장만 된 상태에서는 변수이 형이 숫자형인지 문자열형인지 결정되지 않는다. 즉 실제로 연산이 이루어질 때 연산자가 무엇이냐에 따라 숫자로도 문자열로도 사용이 가능하다. 즉 산술연산식에 변수를 사용하면 숫자로 인식되어 계산되고 문자열 연산에 사용되면 문자열로 인식되어 합쳐지게 된다. 또한 연산의 결과를 받는 변수 c도 연산의 결과에 따라 숫자로 사용되기도 하고 문자로 사용되기도 한다.

따라서 3행에서는 let 이라는 명령어를 통해 뒤에 오는 표현이 “산술연산”임을 알려주고 + 연산자를 통해 덧셈임을 쉘에게 알려준다. 그러면 쉘은 10+10 연산을 수행해 C 변수에 20을 저장한다.

그리고 4행에서 echo 명령을 통해 결과를 출력한다. echo 문에서 변수 앞에 $를 붙인 것은 a가 변수임을 의미한다. $ 없이 echo 문을 사용하면 쉘은 그냥 a+b=c 라고 문자열을 출력해준다.

5행에서는 c라는 변수에 변수a와 변수b의 값을 연결해 그대로 저장하게 된다. 즉 이 행에서 = 는 대입 연산자다. 즉 오른쪽에 나열된 변수의 값을 왼쪽의 변수에 그대로 저장하게 된다. 그래서 6행에서 $c 변수의 내용을 출력했을 때 a와 b에 저장된 10과 10이 연결되어 1010이 출력되는 것이다.

아래의 스크립트도 앞의 스크립트와 같은 결과를 보여준다.

1:  a="10"
2:  b="10"

3:  let c=a+b

4:  echo $a+$b=$c         / * 결과 출력 : 10+10=20   */

4:  c=$a$b

5: echo $c               /* 결과 출력 : 1010  */

1행과 2행에서 변수 a와 b의 초기화에 큰따옴표(“)가 사용되어 언뜻 문자열로만 사용될 것 같지만 실제 연산이 실행될 때 연산식에 따라 숫자로도, 문자열로도 그때 그때 알아서(?) 쉘이 형변환을 통해 연산을 해준다.

쉘에서 변수의 특징을 이해하였다면 문자열 자르기로 넘어가자.

쉘 스크립트에서 문자열 자르기

많은 스크립트 언어와 컴파일 언어에서는 문자열을 합치고 자르는 다양한 이해하기 쉬운 함수를 제공한다. 하지만 쉘에서는 조금 어렵다. 아니 어렵다기보다는 설명이 없이는 난해하다.

문자열을 자릿수에 따라 자르기

표현식설명
${var:start:length}start : 변수로부터 잘라낼 문자의 시작 번호 (0부터 시작됨)
length : start부터의 잘라낼 문자 갯수.
length가 기술되지 않으면 끝까지.

다음의 예제로 살펴보자

IP="192.168.100.10"

echo "IP : "$IP     /* IP 변수를 그대로 출력 : IP=192.168.100.10

echo "12 to 2 : "${IP:12:2}    /* 출력 결과 : 12 to 2 : 10

예제는 위의 하나로 충분하다고 본다.

IP라는 변수에 저장된 문자열 중에서 13번째 부터 2개의 문자열을 잘라내겠다는 의미다. 13번째인데 12가 쓰인 이유는 잘라내기 시작할 start는 0에서 부터 시작하기 때문이다. 일반적인 상식에서는 1이 숫자의 시작으로 생각하겠지만 프로그래밍에서 숫자의 시작은 0인 경우가 많다.

특정 문자(공백, 특수문자 등)를 기준으로 문자열 자르기

쉘 스크립트를 작성하다 보면 특정 문자, 특히 공백(스페이스)문자나 특수기호인 / (슬래시), | (파이프), , (쉼표) 등을 기준으로 문자열을 잘라야 하는 경우가 엄청나게 많다. 이 때 유용하게 사용할 수 있는 명령어가 바로 cut 명령어다.

cut 명령의 입력은 파일이거나 표준입력이다. 파일을 표준입력으로 사용하기 위해서는 cut 명령어의 가장 뒤에 파일명을 붙여주면 된다. 예를 들어 /etc/passwd 파일에서 첫 번째 자리에 있는 ID만 가져오는 명령은 다음과 같이 사용하면 된다.

cut -d : -f1 /etc/passwd

이 명령어는 /etc/passwd의 각 행을 구분자(Delemeter)를 콜론(:)으로 하여 자른 다음 첫 번째 필드 ( -f1 )의 값을 출력하는 명령이다. 이 명령을 실행하면 다음과 같이 ID만 출력이 된다.

[rocky@ap-svr-01 ~]$ cut -d : -f1 /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator
games
ftp
nobody
systemd-coredump
dbus
polkitd
sssd
tss
rpc
setroubleshoot
rpcuser
cockpit-ws
cockpit-wsinstance
sshd
chrony
systemd-oom
rocky
[rocky@ap-svr-01 ~]$

만약 두 번째, 세 번째 필드를 가져오고자 한다면 -f2,3 과 같이 -f 옵션의 값을 지정해주면 된다.

그런데 쉘 스크립트에서는 파일 이외에도 이미 지정된 변수 또는 다른 명령의 출력에서 특정 필드의 값을 가져오고 싶은 경우가 많다. 만약 앞에서 예로 든 IP 변수에서 C 클래스의 값만 가져오고 싶다면 다음과 같이 사용하면 된다.

IP="192.168.100.10"
echo $IP | cut -d . -f3    /*  출력 결과 :  100

이렇게 하면 echo 문의 출력이 cut 명령의 표준입력으로 일시적으로 변경되어 cut 명령은 해당 문자열을 입력으로 받아들여 구분자 . (마침표)를 기준으로 3번째에 해당되는 100만 출력이 된다. 만약 100.10 이 출력되게 하고 싶다면 -f3 을 -f3,4 로 변경해주면 된다. 만약 표준입력의 입력이 여러 라인이라면 각각의 라인에 대해 cut 명령을 수행하여 여러 라인을 출력하게 된다.

만약 -d 옵션을 사용하지 않는다면 cut 명령은 기본 구분자로 공백(space) 문자를 사용하게 된다.

이전 포스트 보기 :[리눅스 기초] shell (쉘)의 이해

다음포스트 포기 : 쉘스크립트에서 이따금씩 사용되는 2>&1 이해하기

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다