Bash
Bash (Borune-again shell, 본 어게인 셸)은 본 셸을 대체하는 자유 소프트웨어로서 GNU 프로젝트를 위해 브라이언 폭스(Brian Fox)가 작성한 유닉스 셸이다. 1989년 발표되어 GNU 운영 체제와 리눅스, 맥 OS X 그리고 다윈 등 운영 체제의 기본 셸로 탑재되어 광범위하게 배포 되었다. 또한 DJGPP와 노벨 넷웨어에 의해 도스로 이식되었고 Cygwin과 MinGW의 배포로 마이크로소프트 윈도로 이식되었다.
이전화면 확인
리눅스에서 GUI가 아닌 텍스트 콘솔상에서 이미 지나가버린 이전 화면을 보는 방법은 아래와 같다.
-
Shift + Page Up
: 이전 화면 보기 -
Shift + Page Down
: 다음 화면 보기
또는 대량의 텍스트를 한 화면씩 확인해야 한다면 more를 PIP로 연결하면 된다.
Category
명령을 찾을 수 없을 경우 command-not-found.com 페이지 참조.
- Bash:read - read built-in 명령 사용 방법
- Bash:Array
- Bash:Mapfile -
mapfile -t variable < <(...)
- Bash:Test
- Bash:RegularExpressions
- Bash:Quoting: 쿼우팅(문자열을 따옴표로 묶는 행위).
- Bash:For: bash의 for문 사용방법.
- Bash:ParameterSubstitution: 매개변수 치환에 대한 설명.
- Bash:Filename: 파일명, 경로 추출 등
- Bash:ExitCode: 특별한 의미를 갖는 종료 코드
- Bash:InternalVariables: 내부 변수 (Internal Variables)
- Bash:PatternMatching: 패턴 매칭 (Pattern Matching)
- Bash:Completion: 자동완성 적용 방법
- Bash:Example
- Bash:Printf
- Bash:PromptSetting
- Bash:Source
- Environment Variables
#!
<< EOF
와 같은 형식으로 stdin 문자열 전달. <(...)
또는 >(...)
- /dev/fd/xxx
과 같이 임시 파일 디스크립터를 생성하여 프로세스에 전달할 수 있게 한다. `...`
또는 $(...)
let
또는 $((...))
( ... )
- Terminal emulator#Truecolor - 터미널 에뮬레이터에서 트루컬러 지원하는 방법 TERM 변수에 대한 내용.
- tmux 설정 방법은 tmux#Truecolor 항목 참조.
- neovim 설정 방법은 Neovim#Truecolor 항목 참조.
make -j4
처럼 병렬 실행하고싶을 때 사용. Recommends
- ShellSpec - full-featured BDD unit testing framework
- shellcheck - ShellCheck, a static analysis tool for shell scripts
- shfmt - A shell parser, formatter, and interpreter with bash support
- Explainshell - match command-line arguments to their help text
주요 환경변수
$(DISPLAY) | 현재 X 윈도우 Display 위치. |
$(HOME) | 사용자 홈 디렉토리. |
$(HOSTNAME) | 호스트 명. |
$(PATH) | 명령어 검색 경로. |
$(PS1) | 프롬프트 설정값. |
$(PWD) | 현재 작업 디렉토리. |
$(SHELL) | 사용하는 쉘. |
$(TERM) | 터미널 종류. |
$(MANPATH) | man 페이지 경로. |
$(LS_COLORS) | ls 명령에서 파일 종류별 색상 지정값. |
전체 환경변수 목록은 env
명령으로 확인할 수 있다.
주요 파일
-
/etc/profile
- 시스템 규모의 환경설정과 시작 프로그램들 -
/etc/bashrc
- 시스템 규모의 alias와 함수(bash 쉘 설정) -
/etc/inputrc
- 시스템 규모의 키 결정(binding)과 기타내용 -
$HOME/.bash_profile
- 사용자 환경설정과 시작 프로그램들(bash 쉘 설정) -
$HOME/.bashrc
- 사용자 alias와 함수들 -
$HOME/.inputrc
- 사용자 키 결정과 기타 내용들
입출력 스트림
- Redirection
- IPC (Interprocess Communication)중 하나
- standard stream을 유저가 정의한 형태(파일 형태)로 Redirect 해주는것을 의미합니다.
- Pipe
- IPC (Interprocess Communication)중 하나
- 한 프로그램의 stdout을 다른프로그램의 stdin으로 전달하는 방법입니다. 즉, 한 프로그램의 출력을 다른 프로그램의 입력값으로 전달해주는 방법입니다.
[명령] > [파일명] | 명령 실행 결과를 파일로 출력. |
[명령] >> [파일명] | 명령 실행 결과를 이 파일에 덧붙여 출력. |
[명령] >& [파일명] | 명령 실행 결과와 에러를 파일로 출력. |
[명령] >>& [파일명] | 명령 실행 결과와 에러를 이 파일에 덧붙여 출력. |
[명령] >! [파일명] | 명령 실행 결과를 이 파일이 이미 존재하더라도 무시하고 출력. |
[명령] >&! [파일명] | 명령 실행 결과와 에러를 이 파일이 이미 존재하더라도 무시하고 출력. |
[명령1] | [명령2] | 명령1의 Output을 명령2의 Input으로 사용하여 실행. |
[명령] > [파일명] | stdout 2 file |
[명령] 2> [파일명] | stderr 2 file |
[명령] 2>&1 | stdout 2 stderr |
[명령] &> [파일명] | stderr and stdout 2 file |
STDOUT and STDERR Redirection
&>word
나 >&word
는 모두 동일하다. 하지만 (필자 경험 상) 플랫폼이나 사용하는 터미널 프로그램 등의 환경이 변화될 경우 작동하지 않을 수 있다. 따라서 아래와 같이 사용하는 것을 추천한다.
Terms
- 와일드카드 문자 (Wildcard character)
- 와일드카드 문자(wildcard character)는 컴퓨터에서 특정 명령어로 명령을 내릴 때, 여러 파일을 한꺼번에 지정할 목적으로 사용하는 기호를 가리킨다. 별표(
*
) 물음표(?
) 등이 사용된다.
메타문자
> | 표준출력을 파일에 기록하는 출력 리다이렉션. |
>> | 표준 출력을 파일 끝에 덧붙이는 출력 리다이렉션. |
< | 파일로부터 표준 입력을 읽는 입력 리다이렉션. |
* | 0개의 이상의 문자와 일치하는 파일 치환 대표 문자. |
? | 단일 문자와 일치하는 파일 치환 대표 문자. |
[...] | 대괄호 사이의 어떤 문자와도 일치하는 파일 치환 대표문자. |
| | 어떤 프로세스의 출력을 다른 프로세스의 입력으로 보내는 파이프 기호. |
; | 명령 순서에 사용. |
<nowiki> | </nowiki> |
&& | 이전의 명령이 성공하면 실행하는 조건부 실행. |
& | |
# | # 문자에 뒤따르는 모든 문자들을 주석 처리. |
$ | 변수 접근. |
ETC
-
\
: 명령어 앞에 사용하면 Alias가 아닌, 원본 명령어를 사용하도록 지정한다.2 (ex.\ls -la
)
TIP
-
!!
: 마지막으로 실행한 명령 재 실행. -
!-2
: 마지막에서 2 번째로 실행된 명령 재 실행. 숫자를 변경할 수 있다. -
!foo
:foo
로 시작하는 가장 최근 명령을 실행합니다. (e.g.!ls
) -
!foo:p
: Print out the command that !foo would run also add it to the command history -
!$
: Run the last word of the previous command (same as Alt + .) -
!$:p
: Print out the word that!$
would substitute -
!*
: Run the previous command except for the last word -
!*:p
: Print out the previous command except for the last word -
^foo^bar
: Run the previous command replacing foo with bar -
$!
: 가장 최근에 실행된 백그라운드 파이프라인의 프로세스 ID 값 -
$$
: 현재 쉘의 PID
계산하기
Bash 쉘에 curl로 다운받은 스크립트 바로 적용
k3s의 샘플 예제 참조:
Stdout Pipe 스크립트와 함께 인자를 전달하는 방법
If the -s
option is present, or if no arguments remain after option processing, then commands are read from the standard input. This option allows the positional parameters to be set when invoking an interactive shell.
Stdout 과 Exit Code 를 함께 받는 방법
function print_checksum
{
echo -n "TEST"
return 1
}
function main1
{
local actual
actual=$(print_checksum)
echo $? # 1
}
function main2
{
local actual=$(print_checksum)
echo $? # 0
}
main1
함수처럼 사용하면 된다. 주의할 점은 local
을 명령 치환 (Command Substitution; $()
)과 함께 사용하면 $?
값이 정상적으로 받아지지 않는다. 이와 관련된 내용은 SC2155 를 참조.
그 밖의 방법으로, 함수에 변수명을 전달하여 eval
을 사용하는 방법이 있다:
function myfunc()
{
local __resultvar=$1
local myresult='some value'
eval $__resultvar="'$myresult'"
}
myfunc result
echo $result
Bash options
- KLDP - 고급 Bash 스크립팅 가이드: Bash를 이용한 쉘 스크립팅 완전 가이드 - 31장. 옵션
- Advanced Bash-Scripting Guide: Chapter 33. Options
옵션은 쉘이나 스크립트의 행동을 변경하도록 설정해 줍니다. set
명령어는 스크립트 안에서 옵션을 켤 수 있게 해 줍니다. 옵션이 적용될 곳에서 set -o -option-name
이라고 하거나 간단하게 set -option-abbrev
라고 하면 됩니다. 이 두 가지 형태는 동일하게 동작합니다.
Enable 시킨 옵션을 다시 Disable 시키고 싶다면 set +o option-name
또는 set +option-abbrev
를 사용하면 된다.
사용할 수 있는 옵션 목록은 bash(1) - Linux manual page # SHELL BUILTIN COMMANDS 항목의 set
부분 참조. (allexport
라고 검색하면 한번에 찾아진다)
단축형 목록은 아래와 같다:
단축형 | 이름 | 뜻 |
| noclobber | 파일이 재지향에 의해 덮어 써지지 않게 막아줌(>| 를 쓰면 가능할 수 있음) |
| (none) | $ 다음에 나오는 큰 따옴표로 쿼우트된 문자열 목록을 보여주기만 하고 명령어를 실행시키지 않음 |
| allexport | 정의된 모든 변수를 export 시킴 |
| notify | 백그라운드로 돌던 작업의 종료를 알려줌(스크립트에서는 그렇게 자주 쓰이지 않음) |
| (none) | |
| noglob | 파일명 확장(globbing)을 끔 |
| interactive | 스크립트를 대화형(interactive) 모드로 돌게함 |
| privileged | 스크립트를 "suid"로 돌게함(조심할 것!) |
| restricted | 스크립트를 제한된 모드로 돌게함(21장 참고) |
| nounset | 정의 안 된 변수 사용시 에러 메세지 출력후 강제 종료 |
| verbose | 명령어 실행 전에 명령어를 표준출력으로 출력 |
| xtrace | -v와 비슷하나 명령어를 확장 |
| errexit | 첫번째 에러에서 스크립트를 취소(0 이 아닌 상태로 종료하는 명령어) |
| noexec | 스크립트의 명령어를 읽기만 하고 실행은 안 함(문법 체크) |
| stdin | 표준입력에서 명령어를 읽어 들임 |
| (none) | 첫번째 명령어 바로 다음에 종료 |
| (none) | 옵션 플래그의 끝. 나머지 인자들은 모두 위치 매개변수로 인식. |
| (none) | 위치 인자로 안 받아 들임. 인자가 주어지면 (-- arg1 arg2), 위치 매개변수는 인자로 세트됨. |
set -x -e
bash의 export명령어
이미 실행된 스크립트에서 source 로 실행한것처럼 하는건 절대 안되는 이유:
이미 실행된 스크립트에서 source 로 실행한것처럼 하는건 절대 안됩니다.
반드시 source test.sh 또는 . test.sh (. 명령)을 써야 합니다.
그 이유는 현재 쉘이 어떤 명령을 실행할때 source나. 명령이 아닌경우 (예를 들면 $ ls ) 현재 쉘이 CHILD 를 포크해서 execlp 로 ls 명령을 실행하고 원래의 쉘은 SIGCLD 가 올때까지,
즉 자식( ls) 이 죽을때 까지 pause() 하고 있기 때문에 원래 쉘로 돌아왔을때는 자식이 export 한것은 전혀 소용 없게 됩니다.
export 는 putenv() 함수를 이용하여 특정문자열("변수명=변수값") 을 환경영역에 옮기는 명령이고 이건 CHILD 들에게만 영향을 미치기 때문입니다.
.env
파일을 읽어 변수를 전부 Export 하는 방법
Bash shell에서 Command History 찾기
inputrc에 다음 내용 추가:
자세한 내용은 GNU Readline 항목 참조.
< vs << vs <<<
명령 | 이름 | 설명 | 예시 |
| Here String | 문자열을 표준 입력으로 전달 | |
| Here Document | 여러 줄 문자열을 표준 입력으로 전달 | |
| Input Redirection | 파일을 표준 입력으로 전달 | |
<<<
의 경우 알기 쉬운 예로, 다음 두 명령은 동일하다:
-
echo "Hello, World!" | wc -w
-
wc -w <<< "Hello, world!"
[ vs [[ vs ( vs ((
- [What's the difference between [ and [ in Bash?
- [추천] [shell - What is the difference between the Bash operators [[ vs vs ( vs ((? - Unix & Linux Stack Exchange
- [추천] [bash - Why does parameter expansion with spaces without quotes work inside double brackets "[[" but not inside single brackets ""? - Unix & Linux Stack Exchange
(…)
서브쉘 (subshell)을 나타냅니다.
$(…)
처럼 앞에 달러 기호가 있는 것은 명령 치환 (command substitution)]:
괄호 안에 명령이 있고 명령의 출력이 명령줄의 일부로 사용됩니다. 3
{…}
중괄호는 명령을 그룹화한다는 점에서 괄호와 같지만 그룹화가 아닌 구문 분석에만 영향을 미칩니다.
-
x=2; { x=4; }; echo $x
는 4를 출력. -
x=2; (x=4); echo $x
는 2를 출력.
Also braces being keywords need to be delimited and found in command position (hence the space after {
and the ;
before }
) whereas parentheses don't. That's just a syntax quirk.
((…))
이중 괄호는 다른 프로그래밍 언어와 유사한 구문을 사용하여 정수에 대한 계산인 산술 명령을 묶습니다.
이 구문은 주로 할당 및 조건문에 사용됩니다.
이것은 ksh/bash/zsh에만 존재하며 일반 sh에는 존재하지 않습니다.
$((…))
표현식의 정수 값으로 확장되는 산술 표현식에서 동일한 구문이 사용됩니다.
[…]
-
[
는 POSIX실행 파일 이다. -
[
는 단순한 실행 파일이다. 그리고]
는 단순히[
의 마지막 아규먼트 이다. - Ubuntu 16.04에는 실제로 coreutils에서 제공하는
/usr/bin/[
에 실행 파일이 있지만 bash 내장 Command 가 우선되어 실행된다.
single brackets surround conditional expressions. Conditional expressions are mostly built on operators such as -n "\(variable" to test if a variable is empty and -e "\)file" to test if a file exists. Note that you need a space around each operator (e.g. [ "\(x" = "\)y" ], not [ "\(x"="\)y" ]), and a space or a character like ; both inside and outside the brackets (e.g. [ -n "\(foo" ], not [-n "\)foo"]).
…
- <code>는 [[Korn 쉘에서 영감을 받은 Bash 확장
double brackets are an alternate form of conditional expressions in ksh/bash/zsh with a few additional features, for example you can write -L \(file && -f \(file</span> to test if a file is a symbolic link to a regular file whereas single brackets require [ -L "\)file" ] && [ -f "\)file" ]. See Why does parameter expansion with spaces without quotes works inside double brackets but not single brackets [? for more on this topic. === 추가: =~
비교 연산 == * [[ ab =~ ab?
</code> 은 POSIX extended regular expression match 이다. ?
는 glob으로 확장되지 않는다.
-
[ a =~ a ]
는 문법 에러 이다. bash에 해당하지 않는다.
그래서 무엇을 사용하나요?
POSIX 확장이 필요하다면 [
, ]
를 사용하라.
몇 가지 복잡한 예시
- [shell - What is the difference between the Bash operators [[ vs vs ( vs ((? - Unix & Linux Stack Exchange
<nowiki>
* <
** [[ a < b ]]: lexicographical comparison
** [ a \< b ]: Same as above. \ required or else does redirection like for any other command. Bash extension.
** expr x"$x" \< x"$y" > /dev/null or [ "$(expr x"$x" \< x"$y")" = 1 ]: POSIX equivalents, see: https://stackoverflow.com/questions/21294867/how-to-test-strings-for-lexicographic-less-than-or-equal-in-bash/52707989#52707989
* && and ||
** [[ a = a && b = b ]]: true, logical and
** [ a = a && b = b ]: syntax error, && parsed as an AND command separator cmd1 && cmd2
** [ a = a ] && [ b = b ]: POSIX reliable equivalent
** [ a = a -a b = b ]: almost equivalent, but deprecated by POSIX because it is insane and fails for some values of a or b like ! or ( which would be interpreted as logical operations
* (
** [[ (a = a || a = b) && a = b ]]: false. Without ( ), would be true because [[ && ]] has greater precedence than [[ || ]]
** [ ( a = a ) ]: syntax error, () is interpreted as a subshell
** [ \( a = a -o a = b \) -a a = b ]: equivalent, but (), -a, and -o are deprecated by POSIX. Without \( \) would be true because -a has greater precedence than -o
** { [ a = a ] || [ a = b ]; } && [ a = b ] non-deprecated POSIX equivalent. In this particular case however, we could have written just: [ a = a ] || [ a = b ] && [ a = b ] because the || and && shell operators have equal precedence unlike [[ || ]] and [[ && ]] and -o, -a and [
* word splitting and filename generation upon expansions (split+glob)
** x='a b'; [[ $x = 'a b' ]]: true, quotes not needed
** x='a b'; [ $x = 'a b' ]: syntax error, expands to [ a b = 'a b' ]
** x='*'; [ $x = 'a b' ]: syntax error if there's more than one file in the current directory.
** x='a b'; [ "$x" = 'a b' ]: POSIX equivalent
* =
** [[ ab = a? ]]: true, because it does pattern matching (* ? [ are magic). Does not glob expand to files in current directory.
** [ ab = a? ]: a? glob expands. So may be true or false depending on the files in the current directory.
** [ ab = a\? ]: false, not glob expansion
** = and == are the same in both [ and [[, but == is a Bash extension.
** case ab in (a?) echo match; esac: POSIX equivalent
** [[ ab =~ 'ab?' ]]: false, loses magic with '' in Bash 3.2 and above and provided compatibility to bash 3.1 is not enabled (like with BASH_COMPAT=3.1)
** [[ ab? =~ 'ab?' ]]: true
* =~
** [[ ab =~ ab? ]]: true, POSIX extended regular expression match, ? does not glob expand
** [ a =~ a ]: syntax error. No bash equivalent.
** printf 'ab\n' | grep -Eq 'ab?': POSIX equivalent (single line data only)
** awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?': POSIX equivalent.
</nowiki>
$* vs $@
- Stackoverflow - Passing arguments with spaces between (bash) script
- SC2124 · koalaman/shellcheck Wiki
- SC2086 · koalaman/shellcheck Wiki
- bash - What's the difference between $@ and $* - Unix & Linux Stack Exchange
자세한 내용은 [tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_02.html Bash 초보자 가이드]를 참조. 분리 방법의 차이로 거의 동일한 작업을 수행하지만 큰따옴표를 사용할 경우 작동 방법이 바뀐다.
-
$*
- 하나에서 시작하여 위치 매개변수로 확장합니다.
- 큰따옴표 내에서 확장이 발생하면 각 매개변수의 값이
IFS
특수 변수의 첫 번째 문자로 구분된 단일 단어로 확장됩니다.- 예를 들면, 문자열을 분리 문자로 합치고 싶을 때
joined=$(IFS=,; echo "${src_paths[*]}")
처럼 사용하면 된다.
- 예를 들면, 문자열을 분리 문자로 합치고 싶을 때
-
$@
- 하나에서 시작하여 위치 매개변수로 확장됩니다.
- 큰따옴표 내에서 확장이 발생하면 각 매개변수가 별도의 단어로 확장됩니다.
또한 배열 사용 시 큰 따옴표 확장은 동일하다. 따라서 #{filelist[*]}
대신 "${filelist[@]}"
를 사용 하는 편이 안전하다.
Example
bash test.sh a b c d
실행시 결과는 a|b|c|d
이다.
bash test.sh a b c d
실행시 결과는 a b c d
이다.
주석
멀티라인 사용시 주석은 `#...`
와 같은 방법으로 사용:
여러 가지 which 방법
다음 명령을 사용하면 된다.
PIPE 입력이 넘어왔는치 확인하는 방법
check if file descriptor of stdin (0) is open or closed:
그 다음 PIPE stdin 결과를 변수에 넣고싶다면:
스크립트 디버깅
| 명령행 옵션 | 동작 |
noexec | | 명령을 실행하지 않고 문법 오류만 검사한다. 대화형 스크립트에서는 무시된다. |
verbose | | 명령을 실행하기 전에 화면에 출력한다. |
xtrace | | 명령행을 처리한 다음 명령을 화면에 출력한다. |
noglob | | 경로명을 확장하지 않는다. (metacharacter 를 사용한 파일 이름 확장을 하지않음. 즉 * 같은 특수문자를 사용할 수 없다) |
-
set -e
: Exit immediately if a command exits with a non-zero status.
Troubleshooting
Bash 사용중 발생되는 문제점에 대하여 정리한다.
스크립트간 공백(Space) 아규먼트 전달 에러
[#\(* vs \(@항목](#\)*_vs_\)@) 참조.
CVE-2014-6271
/bin/sh^M: bad interpreter: No such file or directory
스크립트를 실행하면 아래와 같은 에러가 발생된다.
이 문제는 십중팔구 Windows 개행문자 (CRLF)가 추가되어 발생되는 문제이다. vi -b
를 실행하여 바이너리 모드로 편집하여 ^M
를 지워주면 된다.
Not found "[["
- [Stackoverflow: Bash syntax error: "[: not found"
If your script is executable and you are executing it like ./getconfig.sh, the first line of your script needs to be:
혹시라도 #!/bin/sh
를 적었다면 수정해야 한다.
FOR COMMAND: file loop warning
for
를 사용하여 파일 목록을 LOOP할 경우 in
과 do
사이의 필터 항목에 쿼우팅 (Quoting)을 사용하면 정상적으로 작동하지 않으므로 주의해야 한다.
PS1 설정시 HOME키 동작 오류
PS1
값을 설정할 경우 입력 커서 직전에 \$
값을 설정할 경우, \$
값의 뒤로 색상과 같은 Escape 문자열을 추가하지 않는것이 좋다. HOME키를 사용할 경우 문자열 카운팅 오류가 발생될 수 있다.
warning: setlocale: LC_ALL: cannot change locale
setlocale#warning: setlocale: LC_ALL: cannot change locale 항목 참조.
See also
- Bash 임의코드 실행 취약점 (CVE-2014-6271)
- ls: ls 명령어에 색상넣는 방법 등
- InformationSecurity:CheckList:Unix - Unix계열 시스템의 보안 항목 체크 리스트.
- shell
- Oil - 새로운 Unix 쉘
- xterm.js
- murex - 더 똑똑한 쉘
- terminfo
Favorite site
- Wikipedia (en) Bash (Unix shell)
- Bash 쉘 기본문법
- insford's JspWiki Shell Script 4
- Bash Shell Script Function Examples
- 리눅스 bash에서의 환경변수와 특징
- [추천] 텍스트 처리 명령어
- [추천] Cygwin Bash 한글 설정 및 inputrc 5
- 가장 빨리 만나는 Docker 4장 Docker 이미지 생성하기: Bash 익히기
Basic
Tutorials
Tips
- [추천] Minimal safe Bash script template - 여타 다른 프로그래밍 언어와 다르게 고개만 돌리면 까먹는 Bash 스크립트의, 작고 안전한 템플릿을 소개합니다.