리눅스 셸(bash) 기본 기능 소개
이 글에서 소개할 내용은 굉장히 유용한 기능이라고 생각하며, 셸의 역할인 코드 실행 시의 입/출력에 대한 Proxy, Middleware 역할을 잘 활용하는 기능들이라고 생각한다. 이 글은 리눅스 핵심 레퍼런스의 일부를 참고해 작성하였다.
기준 환경:
Ubuntu 20.04.1 LTS (GCP Compute Engine)
셸은 단순한 호출보다 훨씬 많은 것을 할 수 있다.
1. wildcard: 정규표현식과 유사한 검색을 수행한 결과를 명령의 입력으로 사용
1. 가장 기본이 되는 예제
이름에 wildcard 검색을 수행해 결과를 명령의 입력으로 사용할 수 있다. 이름 일치 기준은 디렉토리이다. 즉 a*
를 셸 명령어에 입력하게 되면, ./a
로 시작하는 파일/디렉토리를 반환한다. 특정 상위 폴더나 하위 폴더를 대상으로 검색하고 싶은 경우 그에 맞는 상대 경로를 입력하면 된다.
(ex 1) ls a*
== ls aardvark adamantium apple
(ex 2) ls githubblog/.*
== ls githubblog/.git githubblog/.deploy_git, ...
위 사진은 기준 디렉토리이다. 여기서 g*
인 파일/디렉토리를 ls -alF
의 매개변수로 주려고 한다.
위 사진은 명령의 결과물로, 실제로 잘 수행됨을 확인할 수 있다.
2.추가 옵션
[문자들...]
: 문자들 중 하나와 일치하는 경우.
[aieou]
: 모음 중 하나. 단 이렇게 찾으려면 파일/디렉토리 이름이 a, i, e, o, u 중 하나여야 한다. (즉 한 글자)
[^문자들...]
, [!문자들...]
: 명시된 문자 이외의 any 문자
[^aieou]
: 자음 중 하나. 단 이렇게 찾으려면 파일/디렉토리 이름이 b, c, d, f, g, … 중 하나여야 한다. (즉 한 글자)
?
: 임의의 한 문자. character 하나의 placeholder라고 생각하면 편리하다.
[githubblo?]
:githubblog
가 있다면 일치한다.
*
: asterisk의 일반적인 의미처럼 아무거나. empty를 포함한 모든 string을 의미. 보통 조합할 때 필수적으로 사용된다.
*[aioeu]
: 모음으로 끝나는 경우*[aioeu]*
: 모음이 포함된 경우[aioeu]*
: 모음으로 시작하는 경우
2. 중괄호 확장: 단순히 가능한 모든 경우의 수를 입력으로 사용
문자열 중간에서 사용되며 가능한 모든 경우의 수로 치환된 후 입력으로 사용된다.
(ex) echo a{b,c,d}e{f,g,h}
== echo abef abeg abeh acef aceg aceh adef adeg adeh
3. 변수: String 타입의 환경 변수
bash 프로파일 관리에 대해선 좀 더 나중에 다루려고 한다.
Windows의 환경 변수와 cmd 환경 변수와 같은 2가지 변수가 있다. 모두 환경 변수이지만 그 범위가 다른데, cmd 환경 변수에 대응되는 Linux에서의 개념이 셸 변수이다. 단 아래의 방법으로 하면 해당 세션(셸)에서만 사용할 수 있으므로 일회성 변수로 생각하면 좋다.
쓰기 : MYVAR=string_value
읽기 : $MYVAR
만약 환경 변수로 저장하고 싶다면, export MYVAR=string_value
와 같이 사용하면 된다. 환경 변수는 printenv
혹은 env
명령으로 확인할 수 있다.
기본으로 제공되는 환경 변수
PATH
: 바이너리 검색 경로의 목록. 콜론으로 구분.
PWD
: 현재 디렉토리 ( OLDPWD
: 마지막으로 방문한 디렉토리 )
HOME
: 홈 디렉토리 ( ex : /home/sb
)
USER
: 로그인명 ( sb
)
4. alias
단순한 String 치환이다.
지정 : alias ll = "ls -lG"
를 입력하면, 이후 셸에서 ll
을 입력하면 ls -lG
가 입력된다.
목록 확인 : alias
만 입력하면 된다.
5. 입출력 redirection
아직 입출력을 파일을 통해 수행해본 적이 없어서 추후 적절한 예시를 추가하려고 한다. 이번 글에서는 개념적으로 그 사용법만 다룬다.
표준 입출력의 지점을 임의의 파일에 수행하게 한다.
입력을 파일의 내용으로 : command < input_file
- 재미있게도
echo < sample.txt
와 같이, echo 명령은 임의의 input 파일의 내용을 출력할 수 없는데, 표준 입출력에서 내용을 읽지 않기 때문이다.
출력을 파일로 :
새로운 파일로 작성 :
command > output_file
기존 파일에 이어 쓰기 :
command >> output_file
오류의 경우 :
command 2> error_file
출력, 오류 모두 :
command >& output_file
혹은command &> output_file
출력, 오류 각각 :
command > output_file 2> error_file
리눅스에서 표준 스트림은 3가지이며 자세한 내용은 위키 백과 (표준 스트림) 참고
6. Pipe
- 각 프로그램이 하나의 일을 잘 할 수 있게 만들 것. 새로운 일을 하려면, 새로운 기능들을 추가하기 위해 오래된 프로그램을 복잡하게 만들지 말고 새로 만들 것.
- 모든 프로그램 출력이 아직 잘 알려지지 않은 프로그램이라고 할지라도 다른 프로그램에 대한 입력이 될 수 있게 할 것. 무관한 정보로 출력을 채우지 말 것. 까다롭게 세로로 구분되거나 바이너리로 된 입력 형식은 피할 것. 대화식 입력을 고집하지 말 것.
- 소프트웨어를, 심지어는 운영 체제일지라도 이른 시기에 수주에 걸쳐 이상적으로 시도해가며 설계하고 만들 것. 어설픈 부분을 버리고 다시 만드는 것을 주저하지 말 것.
- 프로그래밍 작업을 가볍게 하기 위해, 심지어 우회하는 방법으로 도구를 만들고 바로 버릴지라도 어설픈 도움 보다는 도구 사용을 선호할 것.
출처: 위키 백과 (유닉스 철학)
Pipe 연산자는 유닉스 철학을 구현하는 도구 중 하나로, 이 중 2번 규칙을 지키는 도구로 사용된다.
(ex) who | sort | awk '{print $1}' | less
pipe 연산자의 효과를 제대로 소개하는 예제를 만들기엔 아직 아는 명령어가 극히 적어서 추후 제대로 소개하고자 한다. 해당 소개 글이 작성될 경우 이 글에서 링크를 제공하도록 하겠다.
7. 평가식
평가식이란 그 내용이 코드로 해석되는 영역을 말한다. 셸에서의 평가식은 해당 평가식을 셸에서 따로 실행시켰을 때의 결과를 반환하는 형태를 갖는다. 이 평가식의 문법은 크게 두 가지가 있는데,
- backtick :
echo This year is ``date +%Y\``
- This year is 2021
- $() :
echo Next year is $(expr $(date +%Y) + 1)
- Next year is 2022
평가식으로 (5)에서 실패했던 echo < sample.txt
를 평가식으로는 실행할 수 있다: echo $(cat sample.txt)
(`을 사용해도 된다.)
8. 작업 제어
셸에서 수행되는 프로그램은 대개 포그라운드로 실행된다. 즉 사용자와의 인터렉션이 블로킹되는데 셸에서 프로그램을 실행할 때 백그라운드로도 실행시킬 수 있다. 또한 포그라운드와 백그라운드를 넘나들 수 있으며 작업을 정지하고 다시 실행할 수도 있으며 셸 마저 정지할 수도 있다.
백그라운드로 작업 실행 : command ... &
(&
가 핵심이다.)
포그라운드 작업 정지 : Ctrl + Z
백그라운드에서 작업 재개 : `bg {id}``
포그라운드로 작업을 가져와 실행 : fg {id}
현재 수행 중인 작업의 목록 조회 : jobs
현재 셸 정지 : suspend
(현재 실행 중인 셸이 2개 이상이어야 호출 가능하다.)
9. 여러 셸 동시 사용
screen
은 내장 기능이어서 dependency가 추가로 필요하지 않아 사용에 제약이 없지만 그 기능이 적고 불편하다. tmux
가 많이 사용되며 기본으로 설치되는 경우도 있으나(WSL Ubuntu에는 기본으로 설치돼있다.) 둘 모두 사용해본 적이 없어 추후에 다루도록 한다.
TODO :
입출력 Redirection 적극적으로 활용해보기 (특히 알고리즘 테스트 케이스 수행 시)
screen/tmux 모두 사용해보고 비교하기
리눅스 명령어 더 공부하고, pipe로 효과적인 예 만들기
리눅스 셸(bash) 기본 기능 소개