Run The Bridge

shell script master -4- 본문

Cloud/Linux

shell script master -4-

anfrhrl5555 2022. 1. 13. 21:40
728x90
반응형

0. 정규 표현식(Regex) 

다음 사이트에 정규표현식에 대해 잘 정리해놓았다.

https://hamait.tistory.com/342

 

정규표현식 (Regex) 정리

정규표현식은 아주 가끔 쓰기때문에 항상 다시 볼때마다 헷갈리곤 하는데.. 주요 사용예를 정리하여 보았다. 나중에 찾아보기 편하라고~ 정규 표현식의 용어들정규 표현식에서 사용되는 기호를

hamait.tistory.com

 

정규표현식 연습은 아래의 사이트에서 할 수 있다. 우측상단에 javascript를 PCRE로 바꿔서 실습하자.

https://regexr.com/

 

RegExr: Learn, Build, & Test RegEx

RegExr is an online tool to learn, build, & test Regular Expressions (RegEx / RegExp).

regexr.com


1. 정규 표현식 비교(if..fi)

read -p "Are you ready?, press any key(y/n) " -n  # 사용자에게 y/n 입력을 받는다.

read에 변수를 선언하지 않으면 '$REPLY'라는 변수에 담기게 된다.

 

'help read'라는 명령을 통해 더 자세히 알 수 있다.

---

if [[ ! $REPLY =~ ^[Yyf]$ ]]; then exit 1; fi  # '!'는 부정문, '=~'는 정규표현식을 쓰기 위해 써준다.

---

root@kube-master ~/shell_script/shell_cmd # locale='(..)_(..)'  # 변수 선언
root@kube-master ~/shell_script/shell_cmd # if [[ $LANG =~ $locale ]]
> then
> echo "Your country code is ${BASH_REMATCH[2]}."
> ECHO "Your language code is ${BASH_REMATCH[1]}."
> fi
Your country code is US.
Your language code is en.

---

$LANG에는 다음과 같은 정보를 담고 있다.

echo $LANG
en_US.UTF-8

---

BASH_REMATCH에는 en_US의 값을 담고 있다.

echo $BASH_REMATCH
en_US

※ 정규표현식 비교문을 작성할 때 인용부호는 사용하지 말아야 한다.


2. 실습(DRILL) - 사용자의 입력을 받아 문자 or 숫자 구별하기

나는 다음과 같이 짜보았다.. 예외처리를 조금 더 하고싶었는데.. 아직은 부족하다.

#!/bin/bash

read -e -p "Put your answer Word or Number: "

#echo $REPLY

if [[ -z "$REPLY" ]];then  # $REPLY값이 null 값인지 확인다. zero
        echo "You didn't input anything."

elif [[ $REPLY =~ ^[0-9]*$ ]];then  # 숫자로 시작하고, 끝나야 한다.
        echo "You input is Number"

elif [[ $REPLY =~ ^[a-zA-Z]*$ ]];then  # 문자로 시작하고 끝나야 한다.
        echo "You input is Word"

elif [[ $REPLY =~ [a-zA-Z0-9]+ ]];then  # 문자와 숫자 둘 다 검출한다.
        echo "You input is Wore and Number"

elif [[ $REPLY =~ [^a-zA-Z0-9] ]];then  # 특수문자만, 또는 특수문자가 속해있으면 검출한다.
        echo "You have entered a special character"
fi

마지막에 입력받을 때 입력값에 특수문자가 있습니다를 띄우고 싶다.

root@kube-master ~/shell_script/DRILL # ./number_or_word.sh
Put your answer Word or Number: abcdefghklmnopqr
You input is Word

root@kube-master ~/shell_script/DRILL # ./number_or_word.sh
Put your answer Word or Number: 1243245129501235912
You input is Number

root@kube-master ~/shell_script/DRILL # ./number_or_word.sh
Put your answer Word or Number: ``!@#$!@$%!@%~!
You have entered a special character

root@kube-master ~/shell_script/DRILL # ./number_or_word.sh
Put your answer Word or Number: asdsadbc2135325!$@@!%!%!@
You input is Wore and Number

---

해결

#!/bin/bash

read -e -p "Put your answer Word or Number: "

#echo $REPLY

if [[ -z "$REPLY" ]];then  # 변수값이 null인지 확인한다.
        echo "You didn't input anything."

elif [[ $REPLY =~ ^[0-9]*$ ]];then  # 숫자만 있는지 확인한다.
        echo "You input is Number"

elif [[ $REPLY =~ ^[a-zA-Z]*$ ]];then  # 문자만 있는지 확인한다.
        echo "You input is Word"

elif [[ $REPLY =~ [^a-zA-Z0-9] && `echo $?` == 1 ]];then  # 특수문자가 문장 어디든 있으면 '$? == 1'이므로 False가 출력된다.
        echo "You have entered a special character"
        
else
        echo " You input is Word and Number"  # 그 외의 상황
fi

자면서 문득 생각이 들어서 해결할 수 있었다.

root@p-iskim-master ~/iskim # ./word_or_number.sh  # 숫자만 입력
Put your answer Word or Number: 124412412
You input is Number

root@p-iskim-master ~/iskim # ./word_or_number.sh  # 문자만 입력
Put your answer Word or Number: test
You input is Word

root@p-iskim-master ~/iskim # ./word_or_number.sh  # 특수문자만 입력
Put your answer Word or Number: !$@@$@$$%^#$%^@
You have entered a special character

root@p-iskim-master ~/iskim # ./word_or_number.sh  # 숫자+문자 입력
Put your answer Word or Number: asdsad1245124124
 You input is Word and Number

root@p-iskim-master ~/iskim # ./word_or_number.sh
Put your answer Word or Number: @^@^#sdgl;tl43634435436RWET4534#$#$  # 전부 입력
You have entered a special character

3. 명령어(grep)

cat president.txt  # 대통령 이름이 들어간 파일

1. George Washington (1789-1797)    John Adams (1789-1797)
2. John Adams (1797-1801)   Thomas Jefferson (1797-1801)
3. Thomas Jefferson (1801-1809) Aaron Burr (1801-1805)
George Clinton (1805-1809)
4. James Madison (1809-1817)    George Clinton (1809-1812)
None (1812-1813)
Elbridge Gerry (1813-1814)
None (1814-1817)
.
.
.

---

grep으로 하나의 문자을 찾는다. (정규표현식 사용가능)

grep "George.*Washington" president.txt
1. George Washington (1789-1797)    John Adams (1789-1797)

---

George라는 단어가 몇 번 나오는지 확인하기

grep -c George president.txt
7

---

패턴 매칭이 일어난 부분만 출력한다.

grep -o 'George.*' president.txt
George Washington (1789-1797)    John Adams (1789-1797)
George Clinton (1805-1809)
George Clinton (1809-1812)
George M. Dallas (1845-1849)
George Bush (1981-1989)
George Bush (1989-1993) Dan Quayle (1989-1993)
George W. Bush (2001-2009)  Dick Cheney (2001-2009)

---

'-o'는 라인 넘버는 알려주지 않지만, '-b' 옵션을 추가하여 확인할 수 있다.

grep -bo 'George.*' president.txt
3:George Washington (1789-1797)    John Adams (1789-1797)
171:George Clinton (1805-1809)
230:George Clinton (1809-1812)
741:George M. Dallas (1845-1849)
2820:George Bush (1981-1989)
2848:George Bush (1989-1993) Dan Quayle (1989-1993)
2951:George W. Bush (2001-2009)  Dick Cheney (2001-2009)

---

grep '\|' 명령을 통해 두 개의 문자를 매칭할 수 있다.

grep 'Donald\|Obama' president.txt
44. Barack Obama (2009-2017)    Joe Biden (2009-2017)
45. Donald Trump (2017- )   Mike Pence (2017- )

grep -bo 'Donald\|Obama' president.txt
3014:Obama
3061:Donald

---

해당 '\|'가 불편함으로 'egrep'이 탄생하였다.

egrep 'Donald|Obama' president.txt
44. Barack Obama (2009-2017)    Joe Biden (2009-2017)
45. Donald Trump (2017- )   Mike Pence (2017- )

---

grep -E '^\d{1,2}\. George' president.txt  # 값이 출력 되지 않는다

posix expression 방법으로 해결이 가능하다.

grep -E '^[[:digit:]]{1,2}\. George' president.txt  # posix expression
1. George Washington (1789-1797)    John Adams (1789-1797)
41. George Bush (1989-1993) Dan Quayle (1989-1993)
43. George W. Bush (2001-2009)  Dick Cheney (2001-2009)

---

대, 소문자 구별없이 찾는다. 'i'(이건 다들 아시죠 ㅎㅎ?)

grep -i 'richard' president.txt
8. Martin Van Buren (1837-1841) Richard M. Johnson (1837-1841)
34. Dwight D. Eisenhower (1953-1961)    Richard Nixon (1953-1961)
37. Richard Nixon (1969-1974)   Spiro Agnew (1969-1973)

---

해당하는 부분 외에 출력하기 '-v'

grep -i 'richard' president.txt | grep -v 'Nixon'
8. Martin Van Buren (1837-1841) Richard M. Johnson (1837-1841)

---

빈 줄을 찾아준다.

grep -c "^$" president.txt
0  # 0개 이므로 빈 줄이 존재하지 않는다.

---

198*로 시작하는 것은 모두 찾는다.

grep -E '198[[:digit:]]\)$' president.txt
39. Jimmy Carter (1977-1981)    Walter Mondale (1977-1981)
40. Ronald Reagan (1981-1989)   George Bush (1981-1989)

---

앞에 추가로 한 줄, 뒤에 추가로 한 줄 -A, -B

 grep -A1 -B1 -E '198[[:digit:]]\)$' president.txt  # 'A'fter, 'B'efore
Nelson Rockefeller (1974-1977)  # before로 출력
39. Jimmy Carter (1977-1981)    Walter Mondale (1977-1981)  # 이부분 일치
40. Ronald Reagan (1981-1989)   George Bush (1981-1989)  # 이부분 일치
41. George Bush (1989-1993) Dan Quayle (1989-1993)  # after로 출력

---

해당 라인에 첫글자가 숫자가 아닌 모든 걸 출력한다.

egrep '^[^0-9]' president.txt  # 라인의 처음에서 숫자가 아닌 문자

---

/sbin/ifconfig ens32의 결과값은 다음과 같다.

root@kube-master /sbin # /sbin/ifconfig ens32
ens32: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.200.171  netmask 255.255.255.0  broadcast 192.168.200.255
        inet6 fe80::20c:29ff:feee:cc1e  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:ee:cc:1e  txqueuelen 1000  (Ethernet)
        RX packets 38218  bytes 18342767 (17.4 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 24599  bytes 4105177 (3.9 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

해당 위치에서 inet을 뽑아내고, cut을 통해 2번째 인자에서 1번째 인자를 print하는 스크립트

/sbin/ifconfig ens32 | grep 'inet' | cut -d: -f2 | awk '{print $1}'
inet

/sbin/ifconfig ens32 | grep 'inet' | cut -d: -f2 | awk '{print $2}'
192.168.200.171

---

정규식이 아닌 일반 검색용 찾기(find) 명령어

fgrep '(1974' president.txt
38. Gerald Ford (1974-1977) None (1974)
Nelson Rockefeller (1974-1977)

---

※ 정리

grep -c  # grep으로 잡은 단어가 몇 번 나오는지 체크한다.(count)
	ex) grep -c George president.txt
	
grep -o  # 해당 문자를 직접 출력한다.(output)
	ex) grep -o 'George.*' president.txt  
	
grep -bo  # 매칭 문자를 출력하고 라인 넘버를 알려준다.(byte offset)
	ex) grep -bo 'George.*' president.txt
	
grep '\|'  # 두 단어를 동시에 매칭할 수 있다.
	ex) grep 'Donald\|obama' president.txt
	
'\|'이 불편하여 egrep이 탄생하였다.
	ex) egrep 'Donald|obama' president.txt
	
grep -i  # 대, 소문자 구별없이 찾는다.
	ex) grep -i 'richard' president.txt
	
grep -v  # 해당하는 부분 제외 후 출력한다.
	ex) grep -v 'Nixon'
	
grep -c  # 빈 줄을 찾아준다.(count)
	ex) grep -c "^$" president.txt
	
grep -A1 -B1  # 패턴 일치 후 뒤에 1줄, 앞에 1줄을 출력한다.
	ex) grep -A1 -B1 E '198[[:digit:]]\)$' president.txt
	
fgrep  # 정규식이 아닌 일반 검색용 찾기
	ex) fgrep '(1974' president.txt
    
grep -n  # 해당 grep이 몇 번 라인에서 가져왔는지 보여준다.

4. 명령어(sed)

1~100까지 담긴 파일을 하나 만든다.

seq 1 100 > nums

---

15 ~ 18라인까지 출력하는 방법

sed -n '15,18p' nums
15
16
17
18

---

George를 Tom으로 바꾸고 몇 번 라인에서 변경이 이뤄졌는지 출력한다.

sed 's/George/Tom/g' president.txt | grep -n Tom
1:1. Tom Washington (1789-1797)    John Adams (1789-1797)
5:Tom Clinton (1805-1809)
6:4. James Madison (1809-1817)    Tom Clinton (1809-1812)
10:5. James Monroe (1817-1825) Daniel D. Tompkins (1817-1825)
18:11. James K. Polk (1845-1849)   Tom M. Dallas (1845-1849)
64:40. Ronald Reagan (1981-1989)   Tom Bush (1981-1989)
65:41. Tom Bush (1989-1993) Dan Quayle (1989-1993)
67:43. Tom W. Bush (2001-2009)  Dick Cheney (2001-2009)

---

1981를 2981로 변경하고 2981로 변경된 라인 출력

sed 's/1981/2981/g' president.txt | grep -n 2981
63:39. Jimmy Carter (1977-2981)    Walter Mondale (1977-2981)
64:40. Ronald Reagan (2981-1989)   George Bush (2981-1989)

한 라인에 두 번 이상 나온 단어도 모두 변경되었다.( 'g'옵션을 사용하면 된다.), global

---

sed -E '/\(/s/\(.*//g' president.txt | more
1. George Washington

2. John Adams
3. Thomas Jefferson
George Clinton
4. James Madison
None
Elbridge Gerry
None
5. James Monroe
6. John Quincy Adams
7. Andrew Jackson
None
Martin Van Buren
.
.
.

---

sed 's/.$//' president.txt
1. George Washington (1789-1797)    John Adams (1789-1797

2. John Adams (1797-1801)   Thomas Jefferson (1797-1801
3. Thomas Jefferson (1801-1809) Aaron Burr (1801-1805
George Clinton (1805-1809
4. James Madison (1809-1817)    George Clinton (1809-1812
None (1812-1813
Elbridge Gerry (1813-1814
None (1814-1817
5. James Monroe (1817-1825) Daniel D. Tompkins (1817-1825
.
.
.

---

SP=$' ';TAB=$'\t';sed -E 's/'"(${SP}|${TAB})"'{2,5}.+$//' president.txt
1. George Washington (1789-1797)

2. John Adams (1797-1801)
3. Thomas Jefferson (1801-1809) Aaron Burr (1801-1805)
George Clinton (1805-1809)
4. James Madison (1809-1817)
None (1812-1813)
Elbridge Gerry (1813-1814)
None (1814-1817)
5. James Monroe (1817-1825) Daniel D. Tompkins (1817-1825)
6. John Quincy Adams (1825-1829)

---

hello world를 hexdump로 생성한다.

echo -en msdos says "\"hello world\"\x0a\x0d" > msdos.txt

hexdump -C msdos.txt

00000000  6d 73 64 6f 73 20 73 61  79 73 20 22 68 65 6c 6c  |msdos says "hell|
00000010  6f 20 77 6f 72 6c 64 22  0a 0d                    |o world"..|
0000001a

 

마지막에 '0a', '0d'를 CRLF로 볼 수 있다.

---

정규식 패턴매칭을 하여 .$, 즉 마지막 문자를 지운다는 걸 알 수 있다.

sed 's/.$//' msdos.txt > msdos_modified.txt

hexdump -C msdos_modified.txt

00000000  6d 73 64 6f 73 20 73 61  79 73 20 22 68 65 6c 6c  |msdos says "hell|
00000010  6f 20 77 6f 72 6c 64 0a                           |o world.|
00000018

---

콜론(:)으로 서로 구분되어 있는 필드 중, 패턴 매칭을 이용해 원하는 패턴을 찾아서 뽑아낸다.

sed -E 's/([^:]*).*/\1/g' /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator
games
ftp
nobody
systemd-network
dbus
polkitd
tss
abrt
sshd
postfix
docker

---

awk가 더 좋으니까 awk 써라...

awk -F: '{print $1}' /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator
games
ftp
nobody
systemd-network
dbus
polkitd
tss
abrt
sshd
postfix
docker

---


5. 중괄호 확장

noname이 중괄호와 하나씩 결합된다.

root@kube-master ~ # touch noname{1,2,3,4,5,6,7,8,9,}

root@kube-master ~ # ls
anaconda-ks.cfg  noname   noname2  noname4  noname6  noname8  shell_script
helloworld.sh    noname1  noname3  noname5  noname7  noname9  test

---

{..}을 사용해서 한 번에 range을 지정할 수 있다.

root@kube-master ~ # mkdir dir{1..9}

root@kube-master ~ # ls
anaconda-ks.cfg  dir1  dir2  dir3  dir4  dir5  dir6  dir7  dir8  dir9  helloworld.sh  shell_script  test

---

-p 옵션을 줘서 계층 구조로 만들 수 있다.

root@kube-master ~ # mkdir -p newproject/{lib.doc/{pdf,ppt,doc},src,include/sys/bin}
root@kube-master ~ # tree newproject/
newproject/
├── include
│   └── sys
│       └── bin
├── lib.doc
│   ├── doc
│   ├── pdf
│   └── ppt
└── src

8 directories, 0 files

---

eval을 사용하면 입력 라인이 두 번 구문 분석 된다. (코드를 동적으로 평가하는데 사용)

length=40
eval printf -v line '%.0s-' {1..$length}  # 중괄호 확장안에서는 변수 확장이 일어나지 않음, 즉 실행 x
root@kube-master ~ # echo $line
----------------------------------------

만약 eval이 없으면? → 변수 확장이 일어나지 않아 '-'가 한 개만 찍히는 상황을 볼 수 있다.

root@kube-master ~ # printf -v line '%.0s-' {1..$length}
root@kube-master ~ # echo $line
-

---

중괄호 확장은 백업 파일을 만들 때 유용하게 사용 가능하다.(이건 좀 유용한듯...)

 cp president.txt{,.bak}
root@kube-master ~/shell_script/shell_cmd # ls president.txt*
president.txt  president.txt.bak

6. 명령 대체

LANG=C; date  # 환경변수 LANG에 C라는 값과 날짜를 찍는 date 입력
Thu Jan 20 23:20:37 KST 2022

---

명령대체는 $()로 쓰이며, 백 쿼터로도 사용이 가능하다(``, 숫자 1 옆에 있는거) 

root@kube-master ~ # echo "today is $(date)"
today is Thu Jan 20 23:21:38 KST 2022

root@kube-master ~ # LANG=C; echo "today is $`date`"
today is $Thu Jan 20 23:22:02 KST 2022

---

해당 결과가 참이면 디렉토리를 생성하고, 해당 디렉토리로 이동한다. 그 후 pwd를 실행한다.

export DIR1="$( cd dir1 || { mkdir dir1 && cd dir1;}; pwd )"

-bash: cd: dir1: No such file or directory

환경변수에는 다음에 값이 들어가있다.

export  | grep DIR1
declare -x DIR1="/root/dir1"

7. 산술 확장

사칙연산을 비롯한 모듈러 연산을 하기 위해 '(( ))'을 사용한다.

v1=12

v2=$((v1+34))

echo $v2

46

 

---

(($v1+$v2))를 써도 되지만, ((v1+v2))를 사용하여도 값이 동일하다.

root@kube-master ~/dir1 # v3=$(($v1+$v2)); echo $v3
58

root@kube-master ~/dir1 # v3=$((v1+v2)); echo $v3
58

---

증가, 감소 연산자를 사용할 수 있다(++, --)

((v3++))
echo $v3
59

---

if값이 true면 true를 출력하는 문법을 작성하고 산술연산을 사용하면? → False를 토해낸다.

if true; then echo true; fi
true

if ((true)); then echo true; fi

---

0 = true, 1 = False

if ((0)); then echo true; fi  # 해당 문법과 동일하다.

echo $?  # 이전에 입력한 명령이 true, false인지 알 수 있다.

---


8. exit와 종료상태

rm myfile;echo $?
rm: cannot remove 'myfile': No such file or directory
1

---

'||'를 사용해서, 실패했을 때만 사용하는 논리연산자를 사용한다.

rm myfile || { echo 'Could not delete file!'>&2; exit 1; }

 

root@kube-master ~/shell_script/shell_cmd # rm myfile || { echo 'Could not delete file!'>&2; exit 1; }
rm: cannot remove 'myfile': No such file or directory
Could not delete file!
logout

─────────────────────────────────────────────────────────────────────────────────────────────────────────────

Session stopped
    - Press <return> to exit tab
    - Press R to restart session
    - Press S to save terminal output to file

exit 0  # 참을 뜻하므로 쉘 종료

 

exit 1  # 실패를 나타내는 종료 코드, 에러가 발생함


9. 논리 연산 && 와 ||

ls dir || { mkdir dir; }  # 좌측에 명령어가 실패 했을 때, 우측에 실행되는 명령을 적어준다.
ls: cannot access dir: No such file or directory

 

dir이라는 디렉토리가 생성되었다.

pwd
/root/shell_script/shell_cmd/dir

---

cd mydir && ./myscript  # 좌측에 명령어가 성공했을 때, 우측에 명령어 실행(and 개념)
-bash: ./myscript: No such file or directory

기타 예시로 make, make install를 볼 수 있다.

make && make install

10. 로그인쉘과 비 로그인쉘

shopt -q login_shell && echo 'login' || echo 'not-login'
login

'shopt' 명령을 사용해서 언제 어떤 로그인 쉘을 쓰는지 알 수 있다.


11. 명령분리자 ';'

; == '\n' 즉, 줄바꿈을 사용하지 않으면서 한 줄로 사용할 수 있다.

tool=saw;echo $tool  # tool에 saw라는 값 할당
saw

tool=hammer echo $tool  # hammer라는 값이 들어가지 않음
saw

'tool=hammer echo $tool'을 실행했을 대, tool에는 hammer라는 문자가 들어갔지만, 뒤에 echo $tool가 실행되면서

saw가 보이게 된 것 이다.


12. 인라인그룹

ls dir3 && echo "dir directory is here" || mkdir dir3 && echo "dir directory is made"
ls: cannot access dir3: No such file or directory
dir directory is made

디렉토리 3를 찾고, 존재한다면 참을 토해내고, 실패하면 dir3를 생성하고, made 명령을 토해낸다.

pwd
/root/shell_script/shell_cmd/dir3

--

다음과 같이 || { ;}를 사용함으로써 하나의 그룹으로 묶을 수 있다.

ls dir3 && echo "dir directory is here" || { mkdir dir3 && echo "dir directory is made";}

※ 항상 중괄호로 묶고 띄어준 다음에 마지막에 ';'를 써주어야 한다.


감사합니다.

728x90
반응형

'Cloud > Linux' 카테고리의 다른 글

shell script master -6-  (0) 2022.01.27
shell script master -5-  (0) 2022.01.21
i-node 실습  (0) 2022.01.12
shell script master -3-  (0) 2022.01.05
shell script master -2-  (0) 2022.01.03
Comments