Skip to content

Latest commit

ย 

History

History
931 lines (651 loc) ยท 40.5 KB

README.md

File metadata and controls

931 lines (651 loc) ยท 40.5 KB

bash-handbook CC 4.0

์ด ๋ฌธ์„œ๋Š” Bash๋ฅผ ๋ฐฐ์šฐ๊ณ  ์‹ถ์€ ์‚ฌ๋žŒ์„ ์œ„ํ•ด ์ž‘์„ฑ๋˜์—ˆ์ง€๋งŒ ๊นŠ์€ ๋‚ด์šฉ์„ ๋‹ค๋ฃจ์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.

Tip: learnyoubash - ์ด ํ•ธ๋“œ๋ถ ๋‚ด์šฉ์— ๋Œ€ํ•ด์„œ interactiveํ•œ ์›Œํฌ์ˆ์„ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Node Packaged Manuscript

npm์„ ์ด์šฉํ•ด์„œ ์ด ํ•ธ๋“œ๋ถ์„ ์„ค์น˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜์‹ญ์‹œ์˜ค:

$ npm install -g bash-handbook

์„ค์น˜ ํ›„ bash-handbook ๋ช…๋ น์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. $PAGER ์„ ํƒ์ž๋ฅผ ์ด์šฉํ•˜์—ฌ ๋งค๋‰ด์–ผ ํŽ˜์ด์ง€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋‹ˆ๋ฉด ๊ณ„์† ์—ฌ๊ธฐ์„œ ์ฝ์œผ์…”๋„ ๋ฉ๋‹ˆ๋‹ค.

์†Œ์Šค ์ฝ”๋“œ๋Š” ์—ฌ๊ธฐ์— ์žˆ์Šต๋‹ˆ๋‹ค: https://github.com/denysdovhan/bash-handbook

๋ชฉ์ฐจ

Introduction

๋‹น์‹ ์ด ๊ฐœ๋ฐœ์ž๋ผ๋ฉด ์‹œ๊ฐ„์ด ์–ผ๋งˆ๋‚˜ ๊ฐ€์น˜์žˆ๋Š” ์ž์›์ธ์ง€ ์•Œ๊ณ  ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์—…๋ฌด ํ”„๋กœ์„ธ์Šค๋ฅผ ์ตœ์ ํ™”ํ•˜๋Š” ๊ฒƒ์€ ์ผ์„ ์ง„ํ–‰ํ•˜๋Š”๋ฐ ์žˆ์–ด์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์ธก๋ฉด ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ช‡ ๋ฒˆ์ด๊ณ  ๋ฐ˜๋ณตํ•ด์•ผํ•˜๋Š” ์ž‘์—…์—์„œ๋Š” ํšจ์œจ์„ฑ๊ณผ ์ƒ์‚ฐ์„ฑ์„ ๋†’์ด๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค:

  • ์„œ๋ฒ„์—์„œ ์Šคํฌ๋ฆฐ์ƒท์„ ์ฐ๊ฑฐ๋‚˜ ์—…๋กœ๋”ฉํ•˜๋Š” ๊ฒฝ์šฐ
  • ๋งŽ์€ ํ…์ŠคํŠธ๋“ค์„ ๋ณด๊ธฐ ์ข‹๊ฒŒ ๋งŒ๋“ค๊ฑฐ๋‚˜ ์„œ์‹์— ๋งž์ถ”๋Š” ๊ฒฝ์šฐ
  • ํŒŒ์ผ์„ ๋‹ค๋ฅธ ํฌ๋งท์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒฝ์šฐ
  • ํ”„๋กœ๊ทธ๋žจ์—์„œ ๋‚˜์˜ค๋Š” ์ถœ๋ ฅ์„ ๊ตฌ๋ฌธํ•ด์„ํ•˜๋Š” ๊ฒฝ์šฐ

์ด๋Ÿฐ ์ž‘์—…์—์„œ๋Š” Bash๊ฐ€ ๋ฐ”๋กœ ์šฐ๋ฆฌ์˜ ๊ตฌ์„ธ์ฃผ์ž…๋‹ˆ๋‹ค!

Bash๋Š” Bourne shell์„ ๋Œ€์ฒดํ•  GNU ํ”„๋กœ์ ํŠธ๋กœ [Brain Fox][]์˜ํ•ด ์ž‘์„ฑ๋œ Unix ์…ธ์ž…๋‹ˆ๋‹ค. 1989๋…„์— ๋ฐฐํฌ๋˜์—ˆ์œผ๋ฉฐ, Linux์™€ macOS์—์„œ ๊ธฐ๋ณธ ์…ธ๋กœ ์˜ค๋žซ๋™์•ˆ ์‚ฌ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ์šฐ๋ฆฌ๋Š” ์™œ 30๋…„๋„ ๋” ๋œ ๊ธฐ์ˆ ์„ ๋ฐฐ์›Œ์•ผ ๋ ๊นŒ์š”? ๋Œ€๋‹ต์€ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค: ์ด _something_์€ ์˜ค๋Š˜๋‚  ๋ชจ๋“  Unix ๊ธฐ๋ฐ˜ ์‹œ์Šคํ…œ์—์„œ ํšจ์œจ์ ์ธ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•œ ๊ฐ€์žฅ ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ ์ค‘ ํ•˜๋‚˜์ด๋ฉฐ, ์ด๊ฒƒ์ด ๋‹น์‹ ์ด Bash๋ฅผ ๋ฐฐ์›Œ์•ผ ํ•˜๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค. ์ด์ƒ.

์ด ํ•ธ๋“œ๋ถ์€ bash์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ฐœ๋…์„ ์„ค๋ช…ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚œ ์ด ์š”์•ฝํ•œ ๊ฒƒ์ด ๋‹น์‹ ์—๊ฒŒ ๋„์›€์ด ๋˜์—ˆ์œผ๋ฉด ํ•ฉ๋‹ˆ๋‹ค.

Shells and modes

Bash ์…ธ์€ interactive ๋ชจ๋“œ์™€ non-interactive ๋ชจ๋“œ, ๋‘๊ฐ€์ง€ ๋ชจ๋“œ๋กœ ์ž‘์—…์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

Interactive mode

๋‹น์‹ ์ด Ubuntu์—์„œ ์ž‘์—…์„ ํ•˜๊ณ  ์žˆ๋‹ค๋ฉด, 7๊ฐœ๋‚˜ ๋˜๋Š” ๊ฐ€์ƒ ํ„ฐ๋ฏธ๋„์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ์Šคํฌํ†ฑ ํ™˜๊ฒฝ์—์„œ 7๋ฒˆ์งธ ๊ฐ€์ƒ ํ„ฐ๋ฏธ๋„์ธ GUI ๋ชจ๋“œ๋กœ ๋Œ์•„์˜ค๊ณ  ์‹ถ๋‹ค๋ฉด Ctrl-Alt-F7์„ ์ด์šฉํ•˜์—ฌ GUI๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Ctrl-Alt-F1 ํ‚ค๋ฅผ ์ด์šฉํ•˜์—ฌ ์…ธ์„ ์—ด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์นœ์ˆ™ํ•œ GUI๋Š” ์‚ฌ๋ผ์ง€๊ณ  1๋ฒˆ ๊ฐ€์ƒ ํ„ฐ๋ฏธ๋„์ด ๋ณด์ž…๋‹ˆ๋‹ค.

Interactive ๋ชจ๋“œ์—์„œ ์ž‘์—… ์ค‘์ด๋ผ๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณด์ž…๋‹ˆ๋‹ค:

user@host:~$

์—ฌ๊ธฐ์„œ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ Unix ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ls, grep, cd, mkdir, rm๊ณผ ๊ฐ™์€ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๊ณ  ๊ฒฐ๊ณผ๊ฐ’์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์…ธ์ด ์‚ฌ์šฉ์ž์™€ ์ง์ ‘ ์ƒํ˜ธ ์ž‘์šฉ์„ ํ•˜๊ธฐ์— ์šฐ๋ฆฌ๋Š” ์…ธ๊ณผ interactive๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

๊ฐ€์ƒ ํ„ฐ๋ฏธ๋„ ์‚ฌ์šฉ์€ ๋ถˆํŽธํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋กœ, ํ•œ ๋ฒˆ์— ๋ฌธ์„œ๋ฅผ ์ˆ˜์ •ํ•˜๊ณ , ๋‹ค๋ฅธ ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด ๋‹ค์Œ์˜ ๊ฐ€์ƒ ํ„ฐ๋ฏธ๋„ ์—๋ฎฌ๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค:

Non-interactive mode

Non-interactive ๋ชจ๋“œ์—์„œ๋Š” ์…ธ์—์„œ ํŒŒ์ผ์ด๋‚˜ pipe๋ฅผ ํ†ตํ•˜์—ฌ ๋ช…๋ น์„ ์ฝ๊ณ  ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. Interpreter๋Š” ํŒŒ์ผ์ด ๋๋‚˜๊ฒŒ ๋˜๋ฉด ์…ธ ํ”„๋กœ์„ธ์Šค๋Š” ์„ธ์…˜์„ ์ข…๋ฃŒํ•˜๊ณ  ๋ถ€๋ชจ ํ”„๋กœ์„ธ์Šค๋กœ ๋Œ์•„๊ฐ‘๋‹ˆ๋‹ค.

๋‹ค์Œ ๋ช…๋ น์œผ๋กœ non-interactive ๋ชจ๋“œ๋กœ ์…ธ์„ ์‹คํ–‰์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

sh /path/to/script.sh
bash /path/to/script.sh

์œ„ ์˜ˆ์ œ์—์„œ script.sh๋Š” ์…ธ ์ธํ„ฐํ”„๋ฆฌํ„ฐ๊ฐ€ ์•Œ ์ˆ˜ ์žˆ๋Š” ๋ช…๋ น์œผ๋กœ ๊ตฌ์„ฑ๋œ ์ผ๋ฐ˜ ํŒŒ์ผ์ด๊ณ  sh, bash๋Š” ์…ธ ์ธํ„ฐํ”„๋ฆฌํ„ฐ ํ”„๋กœ๊ทธ๋žจ์ž…๋‹ˆ๋‹ค. ๋‹น์‹ ์€ script.sh ํŒŒ์ผ์„ ํŽธํ•œ ์—๋””ํ„ฐ๋กœ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (์˜ˆ, vim, nano, Sublime Text, Atom ๋“ฑ)

chmod ๋ช…๋ น์„ ํ†ตํ•ด ์‹คํ–‰ํŒŒ์ผ๋กœ ๋ณ€๊ฒฝํ•ด์•ผ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‰ฝ๊ฒŒ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

chmod +x /path/to/script.sh

๋˜ํ•œ ์Šคํฌ๋ฆฝํŠธ ์ฒซ ์ค„์€ ํŒŒ์ผ์—์„œ ์‹คํ–‰ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ํ”„๋กœ๊ทธ๋žจ์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ‘œ์‹œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

#!/bin/bash
echo "Hello, world!"

bash๋ณด๋‹ค sh๊ฐ€ ๋” ์ข‹๋‹ค๋ฉด, #!/bin/bash ๊ตฌ๋ฌธ์„ #!/bin/sh๋กœ ๋ณ€๊ฒฝํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ด #! ๋ฌธ์ž์—ด์€ shebang๋กœ ์•Œ๋ ค์ ธ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ ์ด์ œ ๋‹ค์Œ์ฒ˜๋Ÿผ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

/path/to/script.sh

์œ„์—์„œ ์ž‘์„ฑํ•œ ๊ฐ„๋‹จํ•œ trick์€ echo ๋ช…๋ น์„ ์ด์šฉํ•˜์—ฌ ํ„ฐ๋ฏธ๋„์— ํ…์ŠคํŠธ๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.

Shebang ๋ผ์ธ์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ ์ž…๋ ฅํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค:

#!/usr/bin/env bash
echo "Hello, world!"

์ด shebang์—์„œ ์ข‹์€ ์ ์€ ์‹œ์Šคํ…œ PATH ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋กœ ์ง€์ •๋œ ๊ฒƒ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ”„๋กœ๊ทธ๋žจ์„ (์—ฌ๊ธฐ์„œ๋Š” bash) ์‹คํ–‰ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ํŒŒ์ผ ์‹œ์Šคํ…œ์—์„œ ํ”„๋กœ๊ทธ๋žจ path๊ฐ€ ๊ฐ™์ง€ ์•Š์„ ์ˆ˜ ์žˆ๊ธฐ์— ์ฒซ ๋ฒˆ์งธ ๋ฐฉ๋ฒ•๋ณด๋‹ค๋Š” ๋ฐ”๋žŒ์งํ•ฉ๋‹ˆ๋‹ค. ์‹œ์Šคํ…œ PATH๊ฐ€ ๋‹ค๋ฅธ ๋ฒ„์ „์— ๋Œ€ํ•œ ํ”„๋กœ๊ทธ๋žจ์œผ๋กœ ํ‘œ๊ธฐํ•˜๊ณ  ์žˆ์„ ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๊ธฐ์กด ๋ฒ„์ „์ธ bash๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ ์ƒˆ๋กœ์šด ๋ฒ„์ „์œผ๋กœ ์„ค์น˜ํ•˜๊ณ  PATH ๋ณ€์ˆ˜์— ์ƒˆ๋กœ์šด ์œ„์น˜๋ฅผ ์ž…๋ ฅํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ์กด bash๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” #!/bin/bash๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์ƒˆ๋กœ์šด ๋ฒ„์ „์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด #!/usr/bin/env bash๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

Exit codes

๋ชจ๋“  ๋ช…๋ น์€ exit code๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค (return status ๋˜๋Š” exit status). ์ •์ƒ ์ž‘๋™ํ•œ ๋ช…๋ น์€ ํ•ญ์ƒ 0 (zero-code)๋ฅผ, ์ •์ƒ ์ž‘๋™์ด ์•ˆ๋œ ๊ฒฝ์šฐ 0์ด ์•„๋‹Œ ๊ฐ’(error code)์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์‹คํŒจ ์ฝ”๋“œ๋Š” 1์—์„œ 255๊นŒ์ง€์ธ ์–‘์˜ ์ •์ˆ˜์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์Šคํฌ๋ฆฝํŠธ๋กœ ์‚ฌ์šฉํ•  ๋•Œ ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์šฉํ•œ ๋ช…๋ น ์ค‘ ํ•˜๋‚˜๋Š” exit์ž…๋‹ˆ๋‹ค. ์ด ๋ช…๋ น์€ ์‹คํ–‰๋˜๊ณ  ์žˆ๋Š” ๋ช…๋ น์„ ์ข…๋ฃŒํ•˜๊ณ  ์…ธ์— ์ข…๋ฃŒ ์ฝ”๋“œ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ธ์ˆ˜ ์—†์ด exit ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์‹คํ–‰ ์ค‘์ธ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์ข…๋ฃŒ๋œ ํ›„ exit ์ „ ๋งˆ์ง€๋ง‰์œผ๋กœ ์‹คํ–‰ํ•œ ๋ช…๋ น์ด ๋ฐ˜ํ™˜ํ•œ ์ข…๋ฃŒ ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

ํ”„๋กœ๊ทธ๋žจ์ด ์ข…๋ฃŒ๋˜๋ฉด ์…ธ์€ $? ํ™˜๊ฒฝ๋ณ€์ˆ˜์— ๊ทธ exit code๊ฐ€ ํ• ๋‹น๋ฉ๋‹ˆ๋‹ค. $? ๋ณ€์ˆ˜๋Š” ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์‹คํ–‰๋˜์—ˆ๋Š”์ง€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋ณธ ํ…Œ์ŠคํŠธ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์šฐ๋ฆฌ๋Š” ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ข…๋ฃŒํ•˜๊ธฐ ์œ„ํ•ด exit๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ณ , return ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•จ์ˆ˜๋ฅผ ์ข…๋ฃŒํ•˜๊ณ  caller์—๊ฒŒ exit code๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ exit๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ํ•จ์ˆ˜๋ฅผ ์ข…๋ฃŒ_ํ•˜๊ณ _ ํ”„๋กœ๊ทธ๋žจ์„ ์ฃฝ์ž…๋‹ˆ๋‹ค.

Comments

์Šคํฌ๋ฆฝํŠธ๋Š” _์ฃผ์„_์„ ํฌํ•จํ•ด๋„ ๋ฉ๋‹ˆ๋‹ค. ์ฃผ์„์€ shell ์ธํ„ฐํ”„๋ฆฌํ„ฐ์—์„œ ๋ฌด์‹œ๋˜๋Š” ํŠน๋ณ„ํ•œ ๋ฌธ์žฅ์ž…๋‹ˆ๋‹ค. #์œผ๋กœ ์‹œ์ž‘ํ•˜๋ฉฐ ์ค„ ๋ฐ”๊ฟˆ์ด ์žˆ๊ธฐ ์ „๊นŒ์ง€ ์ž‘์„ฑ๋œ ๋‚ด์šฉ์€ ์ฃผ์„ ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด:

#!/bin/bash
# This script will print your username.
whoami

Tip: ์™œ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋งŒ๋“ค์—ˆ๋Š”์ง€์— ๋Œ€ํ•œ ๋‚ด์šฉ์„ ์ฃผ์„์— ๋„ฃ์–ด์•ผ ๋ฉ๋‹ˆ๋‹ค.

Variables

๋‹ค๋ฅธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์ฒ˜๋Ÿผ ๋ณ€์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Bash๋Š” ๋ฐ์ดํ„ฐ ํƒ€์ž…์„ ์•Œ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋ณ€์ˆ˜๋Š” ์˜ค์ง ์ˆซ์ž(numbers)๋‚˜ ํ•˜๋‚˜ ์ด์ƒ์˜ ๋ฌธ์ž์—ด(string)๋กœ ํ• ๋‹นํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณ€์ˆ˜๋Š” 3๊ฐ€์ง€๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: ์ง€์—ญ ๋ณ€์ˆ˜, ํ™˜๊ฒฝ ๋ณ€์ˆ˜, positional arguments ๋ณ€์ˆ˜์ž…๋‹ˆ๋‹ค.

Local variables

**์ง€์—ญ ๋ณ€์ˆ˜ (Local variables)**๋Š” ๋‹จ์ผ ์Šคํฌ๋ฆฝํŠธ ๋‚ด์— ์กด์žฌํ•˜๋Š” ๋ณ€์ˆ˜์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํ”„๋กœ๊ทธ๋žจ์ด๋‚˜ ์Šคํฌ๋ฆฝํŠธ์—์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์ง€์—ญ ๋ณ€์ˆ˜๋Š” = ๊ธฐํ˜ธ๋ฅผ ์ด์šฉํ•˜์—ฌ ํ• ๋‹นํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทœ์น™์ƒ =๊ณผ ๊ฐ’ ์‚ฌ์ด์—๋Š” ๊ณต๋ฐฑ์ด ์žˆ์–ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ฐ’์„ ๋ถ€๋ฅผ ๋•Œ๋Š” $ ๊ธฐํ˜ธ๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ถ€๋ฆ…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด:

username="denysdovhan"  # declare variable
echo $username          # display value
unset username          # delete variable

๋˜ํ•œ local ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹จ์ผ ํ•จ์ˆ˜์— ์ง€์—ญ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํ•จ์ˆ˜๊ฐ€ ์ข…๋ฃŒํ•  ๋•Œ ๋ณ€์ˆ˜๊ฐ€ ํ‘œ์‹œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

local local_var="I'm a local value"

Environment variables

**ํ™˜๊ฒฝ ๋ณ€์ˆ˜ (Environment variables)**๋Š” ํ˜„์žฌ ์…ธ ์„น์…˜์—์„œ ์‹คํ–‰๋˜๊ณ  ์žˆ๋Š” ํ”„๋กœ๊ทธ๋žจ์ด๋‚˜ ์Šคํฌ๋ฆฝํŠธ์—์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๋ณ€์ˆ˜์ž…๋‹ˆ๋‹ค. ์ง€์—ญ ๋ณ€์ˆ˜์™€ ๊ฐ™์ดํ•˜์—ฌ ๋งŒ๋“ค์ง€๋งŒ, export ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

export GLOBAL_VAR="I'm a global variable"

Bash์—์„œ๋Š” ์ „์—ญ ๋ณ€์ˆ˜๊ฐ€ ์ข€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž์ฃผ ์ด๋Ÿฐ ๋ณ€์ˆ˜๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์ˆœ๋žŒํ‘œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค:

๋ณ€์ˆ˜ ์„ค๋ช…
$HOME ํ˜„์žฌ ์‚ฌ์šฉ์ž ํ™ˆ ๋””๋ ‰ํ„ฐ๋ฆฌ.
$PATH ์…ธ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ช…๋ น์–ด๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•œ ์œ„์น˜. ์ฝœ๋ก ์œผ๋กœ ๋ชฉ๋ก์„ ๊ตฌ๋ถ„ํ•จ.
$PWD ํ˜„์žฌ ์ž‘์—… ์ค‘์ธ ๋””๋ ‰ํ„ฐ๋ฆฌ.
$RANDOM 0 ~ 32767 ์‚ฌ์ด์˜ ๋ Œ๋ค ์ธํŠธ๊ฐ’.
$UID ํ˜„์ž ์‚ฌ์šฉ์ž์˜ ์‹ค์žฌ ์‚ฌ์šฉ์ž ID, ์ˆซ์ž๋กœ ํ‘œ๊ธฐ๋จ.
$PS1 ์ฒซ๋ฒˆ์งธ ํ”„๋กฌํ”„ํŠธ ๋ฌธ์ž์—ด.
$PS2 ๋‘๋ฒˆ์งธ ํ”„๋กฌํ”„ํŠธ ๋ฌธ์ž์—ด.

๋‹ค์Œ์— ๋งํฌ์—์„œ bash์— ์žˆ๋Š” ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ํ™•์žฅ ๋ชฉ๋ก์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Positional parameters

**์œ„์น˜ ๋งค๊ฐœ๋ณ€์ˆ˜ (Positional parameters)**๋Š” ํ•จ์ˆ˜๋Š” ๊ฐ’์„ ๊ตฌํ•˜๊ณ  ํ• ๋‹น๋œ ์œ„์น˜์— ๋Œ€ํ•œ ๊ฐ’์„ ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค. ํ•จ์ˆ˜ ๋‚ด๋ถ€์— ์žˆ๋Š” ๊ฒฝ์šฐ, ๋‹ค์Œ ํ‘œ์— ๋‚˜์—ด๋œ ์œ„์น˜ ๋งค๊ฐœ ๋ณ€์ˆ˜์™€ ๊ธฐํƒ€ ํŠน๋ณ„ํ•œ ๋ณ€์ˆ˜์— ๋Œ€ํ•œ ์˜๋ฏธ๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. (์—ญ์ž์ฃผ: Argument๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋“ค์ด๋‹ค.)

๋งค๊ฐœ๋ณ€์ˆ˜ ์„ค๋ช…
$0 ์Šคํฌ๋ฆฝํŠธ ์ด๋ฆ„.
$1 โ€ฆ $9 1 ~ 9๊นŒ์ง€ ๋งค๊ฐœ๋ณ€์ˆ˜ ๋ชฉ๋ก ์š”์†Œ.
${10} โ€ฆ ${N} 10 ~ N๊นŒ์ง€ ๋งค๊ฐœ๋ณ€์ˆ˜ ๋ชฉ๋ก ์š”์†Œ.
$* or $@ $0์„ ์ œ์™ธํ•œ ๋ชจ๋“  ์œ„์น˜ ๋งค๊ฐœ๋ณ€์ˆ˜.
$# ๋งค๊ฐœ๋ณ€์ˆ˜์— ๋Œ€ํ•œ ์ˆซ์ž, $0๋ฅผ ์ œ์™ธํ•˜๊ณ .
$FUNCNAME ํ•จ์ˆ˜ ์ด๋ฆ„ (ํ•จ์ˆ˜ ๋‚ด์—์„œ๋งŒ ๊ฐ’์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค)

๋‹ค์Œ ์˜ˆ์ œ๋ฅผ ์œ„์น˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋‚˜ํƒ€๋‚ด๋ฉด $0='./script.sh', $1='foo', $2='bar':

./script.sh foo bar

๋ณ€์ˆ˜์— ๊ธฐ๋ณธ ๊ฐ’์ด ์กด์žฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ๊ตฌ๋ฌธ์œผ๋กœ ํ•ด๋‹น ๊ฐ’์„ ์ •์˜ํ•˜๋ฉด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค:

 # if variables are empty, assign them default values
: ${VAR:='default'}
: ${$1:='first'}
# or
FOO=${FOO:-'default'}

Shell expansions

_Expansions(ํ™•์žฅ or ์ „๊ฐœ์‹)_์€ _token_์œผ๋กœ ๋‚˜๋ˆ ์ง„ ํ›„ ์ปค๋ฉ˜๋“œ ๋ผ์ธ์—์„œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ๊ณ„์‚ฐ ์‚ฐ์ˆ  ์—ฐ์‚ฐ ๋ฉ”์ปค๋‹ˆ์ฆ˜์—์„œ ๋‹ค๋ฅธ ๋‹จ์–ด๋“ค์€ ๋ช…๋ น์ด ์‹คํ–‰๋˜๊ณ  ๊ฐ’์ด ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์— ํฅ๋ฏธ๊ฐ€ ์žˆ๋‹ค๋ฉด more about shell expansions๋ฅผ ๋ณด์‹ญ์‹œ์˜ค.

Brace expansion

์ค‘๊ด„ํ˜ธ expansion์€ ์ž„์˜์˜ ๋ฌธ์ž์—ด์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. _Filename expansion_๊ณผ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋กœ:

echo beg{i,a,u}n # begin began begun

๋˜ํ•œ ์ค‘๊ด„ํ˜ธ expansion๋Š” ๋ฃจํ”„์—์„œ ๋ฐ˜๋ณตํ•  ๋ฒ”์œ„๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

echo {0..5} # 0 1 2 3 4 5
echo {00..8..2} # 00 02 04 06 08

Command substitution

๋ช…๋ น ์น˜ํ™˜์€ ์šฐ๋ฆฌ๊ฐ€ ๋ช…๋ น์— ๋Œ€ํ•œ ๊ฐ’์„ ๊ตฌํ•˜๊ณ  ๋‹ค๋ฅธ ๋ช…๋ น์ด๋‚˜ ๋ณ€์ˆ˜๋ฅผ ํ• ๋‹นํ•˜๋Š”๋ฐ ๊ทธ ๊ฐ’์„ ํ• ๋‹นํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ช…๋ น์€ `` ์ด๋‚˜ $()๋กœ ๋ฌถ์˜€์„ ๋•Œ ๋ช…๋ น์–ด๋กœ ์น˜ํ™˜์ด ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

now=`date +%T`
# or
now=$(date +%T)

echo $now # 19:08:26

Arithmetic expansion

Bash์—์„œ์˜ ์‚ฐ์ˆ  ์—ฐ์‚ฐ์€ ์ž์œ ๋กญ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ˆ˜์‹์ธ ๊ฒฝ์šฐ์—” $(())๋กœ ๋ฌถ์–ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์‚ฐ์ˆ  expansion ํ˜•์‹์€:

result=$(( ((10 + 5*3) - 7) / 2 ))
echo $result # 9

์‚ฐ์ˆ  expansion์—์„œ ๋ณ€์ˆ˜๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ $ ์ ‘๋‘์‚ฌ ์—†์ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค:

x=4
y=7
echo $(( x + y ))     # 11
echo $(( ++x + y++ )) # 12
echo $(( x + y ))     # 13

Double and single quotes

ํฐ๋”ฐ์˜ดํ‘œ์™€ ์ž‘์€๋”ฐ์˜ดํ‘œ ์‚ฌ์ด์—๋Š” ์ค‘์š”ํ•œ ์ฐจ์ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ํฐ๋”ฐ์˜ดํ‘œ ์•ˆ์—์„œ ๋ณ€์ˆ˜๋‚˜ ๋ช…๋ น ์น˜ํ™˜์ด ์ง„ํ–‰๋ฉ๋‹ˆ๋‹ค. ์ž‘์€๋”ฐ์˜ดํ‘œ ์•ˆ์—์„œ๋Š” ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด:

echo "Your home: $HOME" # Your home: /Users/<username>
echo 'Your home: $HOME' # Your home: $HOME

๊ณต๋ฐฑ์ด ํฌํ•จ๋˜์–ด์žˆ๋Š” ๊ฒฝ์šฐ, ๋”ฐ์˜ดํ‘œ ์•ˆ์— ์ง€์—ญ ๋ณ€์ˆ˜์™€ ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ํ™•์žฅ์‹œ ์ฃผ์˜ํ•ฉ๋‹ˆ๋‹ค. ์ง€๋ฃจํ•œ ์˜ˆ์ œ๋กœ echo๋ฅผ ์ด์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๊ฐ’์— ๋Œ€ํ•˜์—ฌ ์ถœ๋ ฅํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•˜์‹ญ์‹œ์˜ค:

INPUT="A string  with   strange    whitespace."
echo $INPUT   # A string with strange whitespace.
echo "$INPUT" # A string  with   strange    whitespace.

์ฒซ ๋ฒˆ์งธ echo๋Š” $INPUT ๋ณ€์ˆ˜์— ์žˆ๋Š” ๋‹จ์–ด๋“ค์„ 5๊ฐœ์ธ ๋ณ€์ˆ˜๋กœ ์ธ์‹ํ•˜์—ฌ ํ•œ ์นธ์”ฉ ๋„์›Œ echo๋กœ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค. ๋‘ ๋ฒˆ์งธ echo๋Š” ๊ณต๋ฐฑ์„ ํฌํ•จํ•œ $INPUT ๋ณ€์ˆ˜ ์ „์ฒด ๊ฐ’์„ ๋‹จ์ผ ์ธ์ˆ˜๋กœ ๋ฐ›์•„๋“ค์—ฌ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.

์ด์ œ ๋” ๋ณต์žกํ•œ ๊ฒฝ์šฐ๋ฅผ ๋ด…์‹œ๋‹ค:

FILE="Favorite Things.txt"
cat $FILE   # attempts to print 2 files: `Favorite` and `Things.txt`
cat "$FILE" # prints 1 file: `Favorite Things.txt`

์ด๋ จ ๊ฒฝ์šฐ, Favorite-Things.text์™€ ๊ฐ™์€ ์ด๋ฆ„์„ ํŒŒ์ผ ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•ด์„œ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ํ™˜๊ฒฝ ๋ณ€์ˆ˜, ์œ„์น˜ ๋งค๊ฐœ๋ณ€์ˆ˜, ๋‹ค๋ฅธ ๋ช…๋ น (find, cat ๋“ฑ)์„ ์ด์šฉํ•˜์—ฌ ์ถœ๋ ฅํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•ด์•ผ ๋ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์ž…๋ ฅ๊ฐ’์— ๊ณต๋ฐฑ์ด ํฌํ•จ๋˜์–ด ์žˆ์„์ง€๋„ ๋ชจ๋ฅธ๋‹ค๋ฉด ๋”ฐ์˜ดํ‘œ๋กœ ๊ฐ์Œ‰๋‹ˆ๋‹ค.

Arrays

๋‹ค๋ฅธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋“ค์ฒ˜๋Ÿผ bash์—์„œ ๋ฐฐ์—ด(array)๋Š” ์—ฌ๋Ÿฌ ๊ฐ’์„ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š” ๋ณ€์ˆ˜์ž…๋‹ˆ๋‹ค. Bash์—์„œ ๋ฐฐ์—ด์€ zero-based์ž…๋‹ˆ๋‹ค. ์ด๊ฑด ๋ฐฐ์—ด ์ฒซ ์š”์†Œ ์ธ๋ฑ์Šค๊ฐ€ 0์ด๋ผ๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•  ๋•, ํŠน๋ณ„ํ•œ ํ™˜๊ฒฝ ๋ณ€์ˆ˜์ธ IFS๋ฅผ ์กฐ์‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. IFS, Input Field Separator ๋ผ ๋ถˆ๋ฆฌ๋Š” ์ด ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋Š” ๋ฐฐ์—ด ์š”์†Œ๋ฅผ ๊ตฌ๋ณ„ํ•˜๋Š” ๋ฌธ์ž์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ๊ฐ’์€ ๋นˆ ์ŠคํŽ˜์ด์Šค ๊ฐ’์ž…๋‹ˆ๋‹ค. IFS=' '.

Array declaration

Bash๋Š” ๋‹จ์ˆœํ•˜๊ฒŒ ๋ฐฐ์—ด ๋ณ€์ˆ˜์— ์ธ๋ฑ์Šค ๊ฐ’์„ ํ• ๋‹นํ•˜์—ฌ ๋ณ€์ˆ˜๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค:

fruits[0]=Apple
fruits[1]=Pear
fruits[2]=Plum

๋˜ํ•œ ๋ฐฐ์—ด ๋ณ€์ˆ˜๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€๋ฅผ ํ•จ๊ป˜ ํ• ๋‹นํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

fruits=(Apple Pear Plum)

Array expansion

๊ฐ ๋ฐฐ์—ด ์š”์†Œ๋Š” ๋‹ค๋ฅธ ๋ณ€์ˆ˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

echo ${fruits[1]} # Pear

์ „์ฒด ๋ฐฐ์—ด์—์„œ ์ธ๋ฑ์Šค๋ฅผ ๋Œ€์‹ ํ•ด์„œ *, @๋กœ ํ™•์žฅํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

echo ${fruits[*]} # Apple Pear Plum
echo ${fruits[@]} # Apple Pear Plum

์ด ๋‘ ์˜ˆ์ œ์—๋Š” ์ค‘์š”ํ•˜๊ณ  ๋ฏธ๋ฌ˜ํ•œ ์ฐจ์ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค: ๊ณต๋ฐฑ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋ฐฐ์—ด ์š”์†Œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ:

fruits[0]=Apple
fruits[1]="Desert fig"
fruits[2]=Plum

๋ฐฐ์—ด ๊ฐ ์š”์†Œ๋ฅผ ๋‹ค๋ฅธ ํ–‰์— ์ถœ๋ ฅํ•˜๊ณ  ์‹ถ๊ธฐ์— printf ๋‚ด์žฅ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค:

printf "+ %s\n" ${fruits[*]}
# + Apple
# + Desert
# + fig
# + Plum

์Œ... Desert์™€ fig๊ฐ€ ์™œ ๋‹ค๋ฅธ ํ–‰์— ์ถœ๋ ฅ์ด ๋˜๋Š” ๊ฑธ๊นŒ์š”? ๋”ฐ์˜ดํ‘œ๋ฅผ ์‚ฌ์šฉํ•ด๋ด…์‹œ๋‹ค:

printf "+ %s\n" "${fruits[*]}"
# + Apple Desert fig Plum

์ด์ œ๋Š” ์ „๋ถ€ ํ•œ ํ–‰์— ์ถœ๋ ฅ์ด ๋˜๋Š”๊ตฐ์š”! ์ด์ œ ${fruits[@]} ์ฐจ๋ก€์ž…๋‹ˆ๋‹ค:

printf "+ %s\n" "${fruits[@]}"
# + Apple
# + Desert fig
# + Plum

ํฐ๋”ฐ์˜ดํ‘œ ๋‚ด์—์„œ ๋ฐฐ์—ด ์•ˆ์— ์žˆ๋Š” ๊ฐ ์š”์†Œ๋“ค์€ ๋‹ค๋ฅธ ์ธ์ˆ˜๋กœ ${fruits[@]} ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ๋ฐฐ์—ด ์š”์†Œ์— ํฌํ•จ๋œ ๊ณต๋ฐฑ์€ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

Array slice

๋˜ํ•œ slice ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฐ์—ด ์Šฌ๋ผ์ด์Šคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

echo ${fruits[@]:0:2} # Apple Desert fig

์ด ์˜ˆ์ œ๋Š” ${fruits[@]}๋Š” ๋ฐฐ์—ด ์ „์ฒด๋ฅผ ๋‚˜ํƒ€๋‚ด๊ณ , :0:2๋Š” ์ธ๋ฑ์Šค 0์—์„œ ์‹œ์ž‘ํ•ด์„œ 2๋ฒˆ์งธ ๊ฐ’๊นŒ์ง€ ์Šฌ๋ผ์ด์Šคํ•˜์—ฌ ์ถœ๋ ฅํ•˜๋ผ๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค.

Adding elements into an array

๋ฐฐ์—ด์— ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋งค์šฐ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ๊ฐ’์„ ๊ฐ™์ด ํ• ๋‹นํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ๋” ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋‹ค์Œ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

fruits=(Orange "${fruits[@]}" Banana Cherry)
echo ${fruits[@]} # Orange Apple Desert fig Plum Banana Cherry

์œ„ ์˜ˆ์ œ๋Š” ${fruits[@]}๋กœ ๋ชจ๋“  ๋ฐฐ์—ด ๊ฐ’๋“ค์„ ๋ถˆ๋Ÿฌ์˜ค๊ณ , ์ถ”๊ฐ€๋œ ๋‚ด์šฉ๊ณผ ๊ฐ™์ด ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์„ ์ƒ์„ฑํ•œ ๋‹ค์Œ fruits ๋ณ€์ˆ˜์— ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค.

Deleting elements from an array

๋ฐฐ์—ด์—์„œ ์š”์†Œ๋ฅผ ์ œ์™ธํ•˜๋ ค๋ฉด unset ๋ช…๋ น์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค:

unset fruits[0]
echo ${fruits[@]} # Apple Desert fig Plum Banana Cherry

Streams, pipes and lists

Bash๋Š” ๋‹ค๋ฅธ ํ”„๋กœ๊ทธ๋žจ๋“ค๊ณผ ์ถœ๋ ฅ์„ ์กฐ์ž‘ํ•˜๊ธฐ ์œ„ํ•œ ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. Stream์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค๋ฅธ ํ”„๋กœ๊ทธ๋žจ์ด๋‚˜ ํŒŒ์ผ์— ํ”„๋กœ๊ทธ๋žจ ์ถœ๋ ฅ์„ ์ „์†กํ•˜์—ฌ ๋กœ๊ทธ๋ฅผ ์ž‘์„ฑํ•˜๊ฑฐ๋‚˜ ์›ํ•˜๋Š” ์–ด๋–ค ์ž‘์—…์ด๋“  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Pipe๋Š” ์ปจ๋ฒ ์ด์–ด๋ฅผ ๋งŒ๋“ค์–ด ๋ช…๋ น ์‹คํ–‰์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ฐ•๋ ฅํ•˜๊ณ  ์ •๊ตํ•œ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด ๋งค์šฐ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

Streams

Bash๋Š” ์ž…๋ ฅ์„ ๋ฐ›์•„ ์ฐจ๋ก€๋กœ ์ถœ๋ ฅ์„ ๋ณด๋‚ด๊ฑฐ๋‚˜ ๋ฌธ์ž streams ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฐ stream์€ ํŒŒ์ผ์ด๋‚˜ ๋‹ค๋ฅธ ๊ฒƒ์œผ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰์…˜ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ 3๊ฐœ ์„œ์ˆ ์ž๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค:

Code Descriptor ์„ค๋ช…
0 stdin ํ‘œ์ค€ ์ž…๋ ฅ.
1 stdout ์ค€ ์ถœ๋ ฅ.
2 stderr ์˜ค๋ฅ˜ ์ถœ๋ ฅ.

๋ฆฌ๋””๋ ‰์…˜์€ ๋ช…๋ น์—๋ฅผ ๋Œ€ํ•œ ์ถœ๋ ฅ๊ฐ’์ด ์–ด๋””๋กœ ๊ฐˆ ๊ฒƒ์ธ๊ฐ€, ๋ช…๋ น์— ๋Œ€ํ•œ ์ž…๋ ฅ๊ฐ’์ด ์–ด๋””์„œ ์˜ฌ ๊ฒƒ์ธ๊ฐ€์— ๋Œ€ํ•œ ์ œ์–ด๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค. Stream์—์„œ ๋ฆฌ๋””๋ ‰์…˜์„์œ„ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค:

์—ฐ์‚ฐ์ž ์„ค๋ช…
> ์ถœ๋ ฅ ์ „์†ก
&> ์ถœ๋ ฅ๊ณผ ์˜ค๋ฅ˜ ์ถœ๋ ฅ ์ „์†ก
&>> ์ถœ๋ ฅ๊ณผ ์˜ค๋ฅ˜ ์ถœ๋ ฅ์„ ์ „์†ก์ง€์— ์ถ”๊ฐ€
< ์ž…๋ ฅ ์ „์†ก
<< ์š” ๋ฌธ์„œ syntax
<<< ์—ฌ๊ธฐ ๋ฌธ์ž์—ด

๋ฆฌ๋””๋ ‰์…˜์„ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์ œ ์กฐ๊ธˆ:

# output of ls will be written to list.txt
ls -l > list.txt

# append output to list.txt
ls -a >> list.txt

# all errors will be written to errors.txt
grep da * 2> errors.txt

# read from errors.txt
less < errors.txt

Pipes

ํŒŒ์ผ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋‹ค๋ฅธ ํ”„๋กœ๊ทธ๋žจ์—์„œ๋„ ํ‘œ์ค€ ์ŠคํŠธ๋ฆผ ๋ฆฌ๋””๋ ‰์…˜์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Pipes๋ฅผ ์ด์šฉํ•˜์—ฌ ํ”„๋กœ๊ทธ๋žจ ์ถœ๋ ฅ์„ ๋‹ค๋ฅธ ๊ณณ ์ž…๋ ฅ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ์˜ˆ์‹œ์—์„œ๋Š” command1 ์ถœ๋ ฅ์„ command2๋กœ ๋ณด๋‚ด๊ณ , ๊ทธ ์ถœ๋ ฅ์„ ๋‹ค์‹œ command3 ์ž…๋ ฅ์œผ๋กœ ๋ณด๋ƒ…๋‹ˆ๋‹ค:

command1 | command2 | command3

์ด๋Ÿฐ ๊ตฌ์กฐ๋ฅผ ํŒŒ์ดํ”„๋ผ์ธ ์ด๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค.

์‚ฌ์‹ค ๋ช‡ ๊ฐ€์ง€ ํ”„๋กœ๊ทธ๋žจ์„ ํ†ตํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ls -l๋กœ ์ถœ๋ ฅํ•œ ๊ฐ’์—์„œ grep ๋ช…๋ น์„ ์ด์šฉํ•˜์—ฌ .md ํ™•์žฅ์ž๋ฅผ ๊ฐ€์ง„ ํŒŒ์ผ๋งŒ ์ถœ๋ ฅํ•œ ๋’ค less ํ”„๋กœ๊ทธ๋žจ์œผ๋กœ ์ถœ๋ ฅํ•ด์ค๋‹ˆ๋‹ค:

ls -l | grep .md$ | less

ํŒŒ์ดํ”„๋ผ์ธ์—์„œ ์ข…๋ฃŒ ์ƒํƒœ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๋งˆ์ง€๋ง‰ ๋ช…๋ น์ด ๋๋‚˜๋Š” ์‹œ์ ์ž…๋‹ˆ๋‹ค. ํŒŒ์ดํ”„๋ผ์ธ์—์„œ ์ž‘๋™ ์ค‘์ธ ๋ชจ๋“  ๋ช…๋ น์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ์…ธ ์ƒํƒœ๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํŒŒ์ดํ”„๋ผ์ธ์œผ๋กœ ์—ฐ๊ฒฐ๋œ ๋ช…๋ น ์ค‘ ํ•˜๋‚˜๊ฐ€ ์‹คํŒจํ•˜์˜€์„ ๋•Œ, ์—ฐ๊ฒฐ๋œ ํŒŒ์ดํ”„๋ผ์ธ์ด ๋ชจ๋‘ ์‹คํŒจ๋กœ ์„ค์ •ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด pipefail ์˜ต์…˜์„ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

set -o pipefail

Lists of commands

๋ช…๋ น์–ด ๋‚˜์—ด์€ ;, &, &&, || ์—ฐ์‚ฐ์ž๋ฅผ ์ด์šฉํ•˜์—ฌ ํ•˜๋‚˜ ์ด์ƒ ํŒŒ์ดํ”„๋ผ์ธ์— ๋Œ€ํ•œ ์ˆœ์„œ๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

๋ช…๋ น์ด ์ œ์–ด ์—ฐ์‚ฐ์ž &์— ์˜ํ•ด์„œ ์ข…๋ฃŒ๋  ๊ฒฝ์šฐ, ์…ธ์€ ์„œ๋ธŒ ์…ธ์—์„œ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋ช…๋ น์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๋ง๋กœ ํ•˜์ž๋ฉด, ๋ช…๋ น์ด ๋ฐฑ๊ทธ๋ผ์šด๋“œ๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

;๋กœ ๊ตฌ๋ถ„๋œ ๋ช…๋ น์€ ์ฐจ๋ก€๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค: ์ฐจ๋ก€๋กœ. ์…ธ์€ ๊ฐ ๋ช…๋ น์ด ์ข…๋ฃŒ๋ ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค.

# command2 will be executed after command1
command1 ; command2

# which is the same as
command1
command2

&&์™€ ||๋กœ ๊ตฌ๋ถ„๋œ ๋ช…๋ น์–ด ๋‚˜์—ด์€ ๊ฐ๊ฐ _AND_์™€ OR ๋ชฉ๋ก์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

_AND_list_๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

# command2 will be executed if, and only if, command1 finishes successfully (returns 0 exit status)
command1 && command2

_OR-list_๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

# command2 will be executed if, and only if, command1 finishes unsuccessfully (returns code of error)
command1 || command2

AND ๋˜๋Š” OR ๋ช…๋ น์–ด ๋‚˜์—ด์—์„œ ๋ฐ˜ํ™˜ ์ฝ”๋“œ๋Š” ๋งˆ์ง€๋ง‰์œผ๋กœ ์‹คํ–‰ํ•œ ๋ช…๋ น์— ๋Œ€ํ•œ ์ข…๋ฃŒ ์ƒํƒœ์ž…๋‹ˆ๋‹ค.

Conditional statements

๋‹ค๋ฅธ ์–ธ์–ด๋“ค๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Bash ์กฐ๊ฑด๋ฌธ์€ ์–ด๋–ค ์ž‘์—…์„ ์ˆ˜ํ–‰ํ• ์ง€์— ๋Œ€ํ•ด์„œ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ๋Š” [[ ]]๋กœ ๋ฌถ์–ด์•ผ์ง€๋งŒ ํ‘œํ˜„์„ ํ‰๊ฐ€ํ•˜์—ฌ ๊ฒฐ์ •๋ฉ๋‹ˆ๋‹ค.

์กฐ๊ฑด์‹์€ &&์™€ || ์—ฐ์‚ฐ์ž๋ฅผ ์ด์šฉํ•˜์—ฌ _AND_์™€ _OR_๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์™ธ ๋‹ค์–‘ํ•œ ํ‘œํ˜„์„ ์ด์šฉํ•˜์—ฌ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‘ ๊ฐ€์ง€ ์กฐ๊ฑด๋ฌธ์ด ์žˆ์Šต๋‹ˆ๋‹ค: if ๋ฌธ๊ณผ case๋ฌธ.

Primary and combining expressions

[[ ]] (๋˜๋Š” sh์—์„œ๋Š” [ ]) ์•ˆ์— ์žˆ๋Š” ์‹์€ ํ…Œ์ŠคํŠธ ๋ช…๋ น์ด๋‚˜ primaries๋ผ ๋ถ€๋ฆ…๋‹ˆ๋‹ค. ์ด ์ˆ˜์‹๋“ค์€ ์กฐ๊ฑด์— ๋Œ€ํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค๋‹ˆ๋‹ค. ๋‹ค์Œ ํ…Œ์ด๋ธ”์—์„œ๋Š” sh์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก [ ]๋ฅผ ์ด์šฉํ•˜์—ฌ ๋‚˜ํƒ€๋ƒˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ bash์—์„œ ์ด์ค‘ ๋Œ€๊ด„ํ˜ธ์™€ ๋Œ€๊ด„ํ˜ธ์˜ ์ฐจ์ด์— ๋Œ€ํ•ด์„œ ์ด์•ผ๊ธฐํ•ฉ๋‹ˆ๋‹ค.

ํŒŒ์ผ ์‹œ์Šคํ…œ์—์„œ ์ž‘๋™:

Primary Meaning
[ -e FILE ] FILE์ด ์กด์žฌํ•˜๋ฉด(exist), True
[ -f FILE ] FILE์ด ์กด์žฌํ•˜๊ณ  ์ผ๋ฐ˜ ํŒŒ์ผ(regular file)์ด๋ฉด, True.
[ -d FILE ] FILE์ด ์กด์žฌํ•˜๊ณ  ๋””๋ ‰ํ† ๋ฆฌ(directory)์ด๋ฉด, True.
[ -s FILE ] FILE์ด ์กด์žฌํ•˜๊ณ  ๋น„์–ด์žˆ๋‹ค(size more than 0)๋ฉด, True.
[ -r FILE ] FILE์ด ์กด์žฌํ•˜๊ณ  ์ฝ๊ธฐ๊ฐ€๋Šฅํ•˜๋‹ค(readable)๋ฉด, True.
[ -w FILE ] FILE์ด ์กด์žฌํ•˜๊ณ  ์“ฐ๊ธฐ๊ฐ€๋Šฅํ•˜๋‹ค(writable)๋ฉด, True.
[ -x FILE ] FILE์ด ์กด์žฌํ•˜๊ณ  ์‹คํ–‰๊ฐ€๋Šฅํ•˜๋‹ค(xecutable)๋ฉด, True.
[ -L FILE ] FILE์ด ์กด์žฌํ•˜๊ณ  ์‹ฑ๋ณผ๋ฆญ ๋งํฌ(symbolic link)์ด๋ฉด, True.
[ FILE1 -nt FILE2 ] FILE1์ด FILE2 ๋ณด๋‹ค ์ƒˆ๋กœ์šด ํŒŒ์ผ์ž…๋‹ˆ๋‹ค. (FILE1 is newer than FILE2.)
[ FILE1 -ot FILE2 ] FILE1์ด FILE2 ๋ณด๋‹ค ์˜ค๋ž˜๋œ ํŒŒ์ผ์ž…๋‹ˆ๋‹ค. (FILE1 is older than FILE2.)

๋ฌธ์ž์—ด์—์„œ ์ž‘๋™:

Primary Meaning
[ -z STR ] STR์ด ๋น„์—ˆ์Œ (๊ธธ์ด๊ฐ€ 0 (zero)).
[ -n STR ] STR์ด ๋น„์–ด์žˆ์ง€ ์•Š์Œ (๊ธธ์ด๊ฐ€ 0 ์•„๋‹˜ (non-zero))
[ STR1 == STR2 ] STR1๊ณผ STR2๊ฐ€ ๊ฐ™์Œ.
[ STR1 != STR2 ] STR1๊ณผ STR2๊ฐ€ ๊ฐ™์ง€ ์•Š์Œ.

์‚ฐ์ˆ  ์ดํ— ์—ฐ์‚ฐ์ž:

Primary Meaning
[ ARG1 -eq ARG2 ] ARG1๋Š” ARG2์™€ ๊ฐ™๋‹ค (equal).
[ ARG1 -ne ARG2 ] ARG1๋Š” ARG2์™€ ๊ฐ™์ง€ ์•Š๋‹ค (not equal).
[ ARG1 -lt ARG2 ] ARG1๋Š” ARG2๋ณด๋‹ค ์ž‘๋‹ค (less then).
[ ARG1 -le ARG2 ] ARG1๋Š” ARG2๋ณด๋‹ค ์ž‘๊ฑฐ๋‚˜ ๊ฐ™๋‹ค (less than or equal).
[ ARG1 -gt ARG2 ] ARG1๋Š” ARG2๋ณด๋‹ค ํฌ๋‹ค (greater than).
[ ARG1 -ge ARG2 ] ARG1๋Š” ARG2๋ณด๋‹ค ํฌ๊ฑฐ๋‚˜ ๊ฐ™๋‹ค (greater than or equal).

์กฐ๊ฑด์„ combining expressions๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒฐํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

Operation Effect
[ ! EXPR ] EXPR์ด ๊ฑฐ์ง“์ด๋ฉด True.
[ (EXPR) ] EXPR ๊ฐ’ ๋ฐ˜ํ™˜.
[ EXPR1 -a EXPR2 ] ๋…ผ๋ฆฌ AND. EXPR1์™€(and) EXPR2 ์กฐ๊ฑด์ด๋ผ๋ฉด True.
[ EXPR1 -o EXPR2 ] ๋…ผ๋ฆฌ OR. EXPR1๋˜๋Š”(or) EXPR2 ์กฐ๊ฑด์ด๋ผ๋ฉด True.

๋ฌผ๋ก  ๋” ์œ ์šฉํ•œ primaries๊ฐ€ ์กด์žฌํ•˜๋ฉฐ Bash man pages์—์„œ ๋” ์‰ฝ๊ฒŒ ์ฐพ์•„๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Using an if statement

if ๋ฌธ์€ ๋‹ค๋ฅธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์™€ ๊ฐ™์ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๊ด„ํ˜ธ ์•ˆ์— ์žˆ๋Š” ํ‘œํ˜„์‹์ด ์ฐธ์ด๋ฉด then๊ณผ fi ์‚ฌ์ด ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. fi๋Š” ์กฐ๊ฑด๋ถ€๋กœ ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ ๋์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

# Single-line
if [[ 1 -eq 1 ]]; then echo "true"; fi

# Multi-line
if [[ 1 -eq 1 ]]; then
  echo "true"
fi

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ if..else ๋ฌธ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

# Single-line
if [[ 2 -ne 1 ]]; then echo "true"; else echo "false"; fi

# Multi-line
if [[ 2 -ne 1 ]]; then
  echo "true"
else
  echo "false"
fi

๋•Œ๋กœ๋Š” if..else๋ฌธ์ด ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๋งŒํผ ์ถฉ๋ถ„ํ•œ ๊ธฐ๋Šฅ์„ ํ•˜์ง€ ๋ชปํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿด ๊ฒฝ์šฐ, if..elif..else๋ฌธ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ์˜ˆ์ œ๋ฅผ ๋ด…์‹œ๋‹ค:

if [[ `uname` == "Adam" ]]; then
  echo "Do not eat an apple!"
elif [[ `uname` == "Eva" ]]; then
  echo "Do not take an apple!"
else
  echo "Apples are delicious!"
fi

Using a case statement

๋“ค์–ด์˜จ ๊ฐ’์— ๋งž๋Š” ์ž‘์—…์„ ์ง„ํ–‰ํ•  ๋•Œ, ์ค‘์ฒฉ๋œ if๋ฌธ๋ณด๋‹ค ์œ ์šฉํ•œ case๋ฌธ์„ ์ด์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋” ๋ณต์žกํ•œ ์กฐ๊ฑด์ผ ๋•Œ, case๋ฌธ์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค:

case "$extension" in
  "jpg"|"jpeg")
    echo "It's image with jpeg extension."
  ;;
  "png")
    echo "It's image with png extension."
  ;;
  "gif")
    echo "Oh, it's a giphy!"
  ;;
  *)
    echo "Woops! It's not image!"
  ;;
esac

๊ฐ case๋Š” ํŒจํ„ด๊ณผ ์ผ์น˜ํ•˜๋Š” ์‹์ž…๋‹ˆ๋‹ค. | ๊ธฐํ˜ธ๋Š” ์—ฌ๋Ÿฌ ํŒจํ„ด์„ ๋ถ„๋ฆฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋ฉฐ, ) ์—ฐ์‚ฐ์ž๋Š” ํŒจํ„ด ๋ชฉ๋ก ๋์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ๋ช…๋ น๊ณผ ๋งž๋Š”๋‹ค๋ฉด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. *๋Š” ์ •์˜๋œ ํŒจํ„ด์— ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ๋“ค์„ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•œ ํŒจํ„ด์ž…๋‹ˆ๋‹ค. ๋ช…๋ น์— ๋Œ€ํ•œ ๊ฐ ๋ธ”๋ก์€ ;; ์—ฐ์‚ฐ์ž๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ถ„๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

Loops

๋”๋Š” ๋†€๋ผ์ง€ ์•Š๊ฒ ์ฃ . ๋‹ค๋ฅธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋“ค์ฒ˜๋Ÿผ bash์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๋ฐ˜๋ณต๋ฌธ์€ ์ฃผ๊ฑด ์ œ์–ด๋ฌธ์ด true์ผ ๋•Œ ๋ฐ˜๋ณต ์ฒ˜๋ฆฌ ์ฝ”๋“œ ๋ธ”๋ก์„ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

Bash์—์„œ ๋ฐ˜๋ณต๋ฌธ์€ 4๊ฐ€์ง€ ํ˜•์‹์ด ์žˆ์Šต๋‹ˆ๋‹ค: for, while, until, select.

for loop

for ๋ฌธ์€ C ์กฑ๊ณผ ๋งค์šฐ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค:

for arg in elem1 elem2 ... elemN
do
  # statements
done

๊ฐ ๋ฃจํ”„๋ฅผ ํ†ต๊ณผํ•  ๋•Œ, arg์— elem1์—์„œ elemN๊นŒ์ง€์˜ ๊ฐ’์ด ํ• ๋‹น๋ฉ๋‹ˆ๋‹ค. ์™€์ผ๋“œ์นด๋“œ ๋˜๋Š” ์ค‘๊ด„ํ˜ธ expansions๋กœ ๊ฐ’์ด์–ด๋„ ๋ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ, ํ•œ ์ค„๋กœ for๋ฌธ์„ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค๋ฉด ๋‹ค์Œ์ฒ˜๋Ÿผ do ์•ž์— ์„ธ๋ฏธ์ฝœ๋ก ์„ ๋ถ™์—ฌ์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

for i in {1..5}; do echo $i; done

for..in..do ํ˜•์‹์ด ์ด์ƒํ•˜๋‹ค๋ฉด ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ C์™€ ๊ฐ™์€ ์Šคํƒ€์ผ๋กœ for๋ฌธ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

for (( i = 0; i < 10; i++ )); do
  echo $i
done

๋””๋ ‰ํ„ฐ๋ฆฌ์—์„œ ๊ฐ ํŒŒ์ผ์— ๊ฐ™์€ ์ž‘์—…์„ ์ง„ํ–‰ํ•˜๋ ค๊ณ  ํ•  ๋•Œ for๋ฌธ์„ ์‚ฌ์šฉํ•˜๋ฉด ํŽธํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋ชจ๋“  .bash ํŒŒ์ผ์„ script ํด๋”๋กœ ์˜ฎ๊ธฐ๊ณ  ์‹คํ–‰ ๊ถŒํ•œ์„ ์ค€๋‹ค๋ฉด, ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

#!/bin/bash

for FILE in $HOME/*.bash; do
  mv "$FILE" "${HOME}/scripts"
  chmod +x "${HOME}/scripts/${FILE}"
done

while loop

while ๋ฐ˜๋ณต๋ฌธ์€ ์กฐ๊ฑด์„ ํ…Œ์ŠคํŠธํ•˜๊ณ  _true_๊ฐ€ ๋  ๋•Œ๊นŒ์ง€ ๋ช…๋ น์„ ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค. ์กฐ๊ฑด์€ if..then ์กฐ๊ฑด์—์„œ primary ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ๊ณผ ๋‹ค๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ while ๋ฐ˜๋ณต๋ฌธ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

while [[ condition ]]
do
  # statements
done

for ๋ฐ˜๋ณต๋ฌธ๊ณผ ๊ฐ™์ด ๊ฐ™์€ ์ค„์— do๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์•ž์— ์„ธ๋ฏธ์ฝœ๋ก ์„ ๋ถ™์—ฌ์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์ œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

#!/bin/bash

# Squares of numbers from 0 through 9
x=0
while [[ $x -lt 10 ]]; do # value of x is less than 10
  echo $(( x * x ))
  x=$(( x + 1 )) # increase x
done

until loop

until ๋ฐ˜๋ณต๋ฌธ์€ while ๋ฐ˜๋ณต๋ฌธ๊ณผ๋Š” ์ •๋ฐ˜๋Œ€๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. while๊ณผ ๊ฐ™์ด ํ…Œ์ŠคํŠธ ์กฐ๊ฑด์„ ํ™•์ธํ•˜๊ณ  ๊ทธ ์กฐ๊ฑด์ด false ๋  ๋•Œ๊นŒ์ง€ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค:

until [[ condition ]]; do
  #statements
done

select loop

select ๋ฐ˜๋ณต๋ฌธ์€ ์‚ฌ์šฉ์ž ๋งค๋‰ด์–ผ์„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค๋‹ˆ๋‹ค. for ๋ฐ˜๋ณต๋ฌธ๊ณผ ๊ฐ™์€ ๊ตฌ๋ฌธ์œผ๋กœ ๋˜์–ด์žˆ์Šต๋‹ˆ๋‹ค:

select answer in elem1 elem2 ... elemN
do
  # statements
done

select์€ ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•˜๋ฉด, ์—ฐ์†๋œ ์ˆซ์ž๋“ค๊ณผ ์Šคํฌ๋ฆฐ์— ๋ชจ๋“  elem1..elemN์„ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ $? (PS3 ๊ฐ’)๊ณผ ๊ฐ™์ด ๋ณด์ž…๋‹ˆ๋‹ค. ์ž…๋ ฅํ•œ ๋Œ€๋‹ต์€ answer์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. answer๊ฐ€ 1..N ์‚ฌ์ด ์ˆ˜์ธ ๊ฒฝ์šฐ, statements๊ฐ€ ์‹คํ–‰๋˜๊ณ  select๋Š” ๋‹ค์Œ์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ break ๋ฌธ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ž‘๋™ ์˜ˆ์ œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

#!/bin/bash

PS3="Choose the package manager: "
select ITEM in bower npm gem pip
do
  echo -n "Enter the package name: " && read PACKAGE
  case $ITEM in
    bower) bower install $PACKAGE ;;
    npm)   npm   install $PACKAGE ;;
    gem)   gem   install $PACKAGE ;;
    pip)   pip   install $PACKAGE ;;
  esac
  break # avoid infinite loop
done

์ด ์˜ˆ์ œ์—์„œ๋Š” ์‚ฌ์šฉ์ž์—๊ฒŒ ์‚ฌ์šฉํ•  ์–ด๋–ค ํŒจํ‚ค์ง€ ๊ด€๋ฆฌ์ž {s,he}๋ฅผ ๋ฌป์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํŒจํ‚ค์ง€ ๊ด€๋ฆฌ์ž๋ฅผ ์„ ํƒํ•˜๊ณ  ์„ค์น˜ํ•  ํŒจํ‚ค์ง€๋ฅผ ๋ฌป์Šต๋‹ˆ๋‹ค.

์‹คํ–‰ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ช…๋ น์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

$ ./my_script
1) bower
2) npm
3) gem
4) pip
Choose the package manager: 2
Enter the package name: bash-handbook
<installing bash-handbook>

Loop control

๋ฐ˜๋ณต๋ฌธ์ด ์ผ๋ฐ˜์ ์œผ๋กœ ๋๋‚ด๊ฑฐ๋‚˜ ํŠน์ • ๋‹จ๊ณ„ ์ „์— ๋ฉˆ์ถœ ๋•Œ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ์—” ์…ธ ๋‚ด์žฅ ํ•จ์ˆ˜์ธ break๊ณผ continue ๋ฌธ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‘˜ ๋‹ค ๋ชจ๋“  ๋ฐ˜๋ณต๋ฌธ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

break ๋ฌธ์€ ๋๋‚˜๊ธฐ ์ „ ํ˜„์žฌ ๋ฐ˜๋ณต๋ฌธ์—์„œ ๋‚˜๊ฐˆ ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฏธ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

continue ๋ฌธ์€ ํ•œ๋‹จ๊ณ„๋ฅผ ๋„˜์–ด์„œ ์ง„ํ–‰๋ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

for (( i = 0; i < 10; i++ )); do
  if [[ $(( i % 2 )) -eq 0 ]]; then continue; fi
  echo $i
done

์œ„ ์˜ˆ์ œ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค๋ฉด, 0์—์„œ 9๊นŒ์ง€์˜ ๋ชจ๋“  ์ง์ˆ˜๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.

Functions

์Šคํฌ๋ฆฝํŠธ์—์„œ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜๊ณ  ๋ถˆ๋Ÿฌ ์‚ฌ์šฉ ๊ฐ€๋Šฅ ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์ฒ˜๋Ÿผ Bash์—์„œ ํ•จ์ˆ˜๋Š” ์ฝ”๋“œ ๋ฉ์–ด๋ฆฌ์ง€๋งŒ ์ฐจ์ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

Bash์—์„œ ํ•จ์ˆ˜๋Š” ํ•จ์ˆ˜ _์ด๋ฆ„_์œผ๋กœ ๊ทธ๋ฃนํ™”ํ•œ ๋ช…๋ น์ž…๋‹ˆ๋‹ค. ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋‹ค๋ฅธ ํ”„๋กœ๊ทธ๋žจ๊ณผ ๊ฐ™์ด ํ˜ธ์ถœํ•˜๋ฉฐ, ๊ทธ๋ƒฅ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜๋ฉด ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•จ์ˆ˜๋ฅผ ์„ ์–ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

my_func () {
  # statements
}

my_func # call my_func

ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์ „ ์„ ์–ธ์„ ํ•˜์—ฌ์•ผ์ง€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•จ์ˆ˜๋Š” ์ธ์ˆ˜๋ฅผ ์ทจํ•ด ๊ฒฐ๊ณผ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค -- ์ข…๋ฃŒ ์ฝ”๋“œ. ์ธ์ˆ˜๋Š” ํ•จ์ˆ˜๋‚ด non-interactive ๋ชจ๋“œ์—์„œ ์Šคํฌ๋ฆฝํŠธ์— ์ฃผ์–ด์ง„ ์ธ์ˆ˜์™€ ๊ฐ™์ด ์ทจ๊ธ‰๋ฉ๋‹ˆ๋‹ค. -- positional parameters๋ฅผ ์‚ฌ์šฉํ•ด์„œ. ๊ฒฐ๊ณผ ์ฝ”๋“œ๋Š” return ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

ํ•จ์ˆ˜๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์‹คํ–‰๋œ ๊ฒƒ์„ ๋‚˜ํƒ€๋‚ด๋Š” ์ด๋ฆ„์„ ๊ฐ€์ง€๊ณ  0์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

# function with params
greeting () {
  if [[ -n $1 ]]; then
    echo "Hello, $1!"
  else
    echo "Hello, unknown!"
  fi
  return 0
}

greeting Denys  # Hello, Denys!
greeting        # Hello, unknown!

์ด๋ฏธ ์ข…๋ฃŒ ์ฝ”๋“œ์— ๋Œ€ํ•ด์„œ ์ด์•ผ๊ธฐํ•˜์˜€์Šต๋‹ˆ๋‹ค. return ๋ช…๋ น์€ ์ธ์ˆ˜ ์—†์ด ๋งˆ์ง€๋ง‰์œผ๋กœ ์‹คํ–‰ํ•œ ๋ช…๋ น์— ๋Œ€ํ•œ ์ข…๋ฃŒ ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  return 0์œผ๋กœ ๊ตฌ์„ฑํ•ด ๋‘๋ฉด ์ •์ƒ ์ข…๋ฃŒ ์ฝ”๋“œ๋กœ 0์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

Debugging

์…ธ์—์„œ๋„ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋””๋ฒ„๊น…ํ•  ์ˆ˜ ์žˆ๋Š” ํˆด์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋””๋ฒ„๊ทธ ๋ชจ๋“œ๋กœ ์‹คํ–‰ํ•˜๋ ค๋ฉด ์Šคํฌ๋ฆฝํŠธ shebang์— ํŠน๋ณ„ํ•œ ์˜ต์…˜์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

#!/bin/bash options

์ด ์˜ต์…˜์€ ์…ธ ๋™์ž‘์„ ๋ณ€๊ฒฝํ•˜๋Š” ์„ค์ •์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ ํ‘œ์—์„œ ๋„์›€์ด ๋˜๋Š” ๊ฒƒ๋“ค์— ๊ด€ํ•ด ์„ค๋ช…ํ•ด๋’€์Šต๋‹ˆ๋‹ค:

Short Name ์„ค๋ช…
-f noglob ํŒŒ์ผ ์ด๋ฆ„ ํ™•์žฅ (globbing)์„ ๋น„ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค.
-i interactive ์Šคํฌ๋ฆฝํŠธ๋ฅผ interactive ๋ชจ๋“œ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.
-n noexec ๋ช…๋ น์„ ์ฝ์Šต๋‹ˆ๋‹ค๋งŒ ์‹คํ–‰ํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค (๋ฌธ๋ฒ• ์ฒดํฌ).
pipefail ์–ด๋–ค ๋ช…๋ น์ด ์ œ๋Œ€๋กœ ์‹คํ–‰๋˜์ง€ ๋ชปํ•˜์—ฌ ๋งˆ์ง€๋ง‰ ๋ช…๋ น์ด ์‹คํŒจํ•œ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ๋ฉด, ํŒŒ์ดํ”„๋ผ์ธ ์˜ค๋ฅ˜๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
-t โ€” ์ฒซ ๋ช…๋ น ํ›„ ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค.
-v verbose ๊ฐ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๊ธฐ ์ „ stderr๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.
-x xtrace ๊ฐ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๊ธฐ ์ „ ๋ช…๋ น๊ณผ stderr์— ํ™•์žฅ ๋ณ€์ˆ˜๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด -x์˜ต์…˜์„ ์‚ฌ์šฉํ•ด ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค:

#!/bin/bash -x

for (( i = 0; i < 3; i++ )); do
  echo $i
done

์ด ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•˜๊ฒŒ๋˜๋ฉด ๋‹ค๋ฅธ ์ •๋ณด๋“ค๊ณผ ํ•จ๊ป˜ stdout ๋ณ€์ˆซ๊ฐ’์„ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค:

$ ./my_script
+ (( i = 0 ))
+ (( i < 3 ))
+ echo 0
0
+ (( i++  ))
+ (( i < 3 ))
+ echo 1
1
+ (( i++  ))
+ (( i < 3 ))
+ echo 2
2
+ (( i++  ))
+ (( i < 3 ))

๋•Œ๋•Œ๋กœ ์Šคํฌ๋ฆฝํŠธ ์ผ๋ถ€๋ฅผ ๋””๋ฒ„๊น… ํ•ด์•ผ ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ set ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ด ๋ช…๋ น์œผ๋กœ ์˜ต์…˜์„ ํ™œ์„ฑํ™”ํ•˜๊ณ  ๋น„ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ๋ฒ•์€ -์„ ์‚ฌ์šฉํ•˜์—ฌ ํ™œ์„ฑํ™” ์‹œํ‚ค๊ณ , +๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋น„ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค:

#!/bin/bash

echo "xtrace is turned off"
set -x
echo "xtrace is enabled"
set +x
echo "xtrace is turned off again"

Afterword

๋‚˜๋Š” ์ด ์ž‘์€ ํ•ธ๋“œ๋ถ์ด ์žฌ๋ฏธ์žˆ๊ณ  ๋„์›€์ด ๋˜์—ˆ์œผ๋ฉด ํ•ฉ๋‹ˆ๋‹ค. ๋‚˜ ์ž์‹ ์ด Bash์— ๋Œ€ํ•œ ๊ธฐ๋ณธ์„ ์žŠ์ง€ ์•Š๊ธฐ ์œ„ํ•ด ์ด ํ•ธ๋“œ๋ถ์„ ์ž‘์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค. ๊ฐ„๊ฒฐํ•˜๊ณ  ์˜๋ฏธ ์žˆ๋Š” ๊ฒƒ์„ ๊ธฐ๋กํ•˜๋ ค ํ•˜์˜€์Šต๋‹ˆ๋‹ค๋งŒ, ์ž˜ ์•ˆ๋˜์—ˆ๋‹ค๋ฉด ์ดํ•ดํ•ด ์ฃผ์…จ์œผ๋ฉด ํ•ฉ๋‹ˆ๋‹ค.

์ด ํ•ธ๋“œ๋ถ์€ bash์— ๋Œ€ํ•œ ๋‚ด ๊ฒฝํ—˜์„ ์ด์•ผ๊ธฐํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๊ทธ๋ ‡๊ฒŒ ํฌ๊ด„์ ์œผ๋กœ ์„œ์ˆ ๋˜์ง€ ์•Š์•˜๊ธฐ์— ๋” ๋งŽ์€ ๊ฒƒ์„ ์›ํ•œ๋‹ค๋ฉด man bash๋ฅผ ์‹คํ–‰ํ•ด์„œ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค.

์ปจํŠธ๋ฆฌ๋ทฐ์…˜์€ ์ ˆ๋Œ€์ ์œผ๋กœ ํ™˜์˜ํ•˜๋ฉฐ ์–ด๋–ค ์งˆ๋ฌธ์ด๋‚˜ ์ด์Šˆ์— ๋Œ€ํ•ด ๋‚˜์—๊ฒŒ ์•Œ๋ ค์ฃผ์‹ญ์‹œ์˜ค. ์ด์Šˆ๋ฅผ ๋งŒ๋“ค์–ด์„œ ๋ง์ด์ฃ .

์ด ํ•ธ๋“œ๋ถ์„ ์ฝ์–ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

Want to learn more?

์—ฌ๊ธฐ๋Š” Bash์— ๋Œ€ํ•ด์„œ ๋” ์•Œ ์ˆ˜ ์žˆ๋Š” ๋ฌธ์„œ ๋ชฉ๋ก์ž…๋‹ˆ๋‹ค:

  • Bash man ํŽ˜์ด์ง€. Bash๊ฐ€ ์‹คํ–‰๋˜๋Š” ์—ฌ๋Ÿฌ ํ™˜๊ฒฝ์—์„œ ๋„์›€๋ง ์‹œ์Šคํ…œ man์„ ์‚ฌ์šฉํ•˜์—ฌ Bash์— ๊ด€ํ•œ ๋‚ด์šฉ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์‹คํ–‰ ๋ช…๋ น์–ด๋Š” man bash์ž…๋‹ˆ๋‹ค. man ๋ช…๋ น์— ๋Œ€ํ•œ ๋” ๋งŽ์€ ๋‚ด์šฉ์„ ํ™•์ธํ•˜๊ณ  ์‹ถ์œผ๋ฉด The Linux Information Project์—์„œ ํ˜ธ์ŠคํŒ… ๋˜๊ณ  ์žˆ๋Š” "The man Command" ์›นํŽ˜์ด์ง€๋ฅผ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค.
  • "Bourne-Again SHell manual"์€ ๋งŽ์€ ํ˜•์‹ (HTML, Info, TeX, PDF, Texinfo)์œผ๋กœ ๋˜์–ด์žˆ์Šต๋‹ˆ๋‹ค. https://www.gnu.org/์—์„œ ํ˜ธ์ŠคํŒ… ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. 2016๋…„ 1์›” ํ˜„์žฌ ๋ฒ„์ „ 4.3์ด๋ฉฐ, ๋งˆ์ง€๋ง‰ ์—…๋ฐ์ดํŠธ๋Š” 2015๋…„ 2์›” 2์ผ์ž…๋‹ˆ๋‹ค.

Other resources

  • awesome-bash๋Š” Bash ์Šคํฌ๋ฆฝํŠธ์™€ ๋ฆฌ์†Œ์Šค์—๋Œ€ํ•œ ๋ชจ์Œ
  • awesome-shell๋Š” ์…ธ ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ๋‹ค๋ฅธ ๋ชจ์Œ
  • bash-it ์ผ์ƒ ์—…๋ฌด์—์„œ ์‚ฌ์šฉํ•  ์…ธ ์Šคํฌ๋ฆฝํŠธ์™€ ๊ฐœ์ธํ™”๋œ ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐœ๋ฐœ๊ณผ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ ๊ฐ•๋ ฅํ•œ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  • dotfiles.github.io๋Š” ๋‹ค์–‘ํ•œ dotfile ์ปฌ๋ ‰์…˜๊ณผ bash์™€ ๋‹ค๋ฅธ ์…ธ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์…ธ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์†Œ๊ฐœํ•˜๋Š” ๊ณณ์ž…๋‹ˆ๋‹ค.
  • learnyoubash๋Š” ์ฒซ bash ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜๋Š” ๊ณณ์ž…๋‹ˆ๋‹ค.
  • shellcheck๋Š” ์…ธ ์Šคํฌ๋ฆฝํŠธ์— ๋Œ€ํ•œ ์ •์  ๋ถ„์„ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. www.shellcheck.net ์›นํŽ˜์ด์ง€๋กœ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์„ค์น˜์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ koalaman/shellcheck์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ, Stack Overflow์—์„œ tagged as bash๋Š” ๋งŽ์€ ์งˆ๋ฌธ์— ๋Œ€ํ•œ ๋‹ต์„ ์–ป์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ทธ๊ฒƒ์„ ํ†ตํ•ด์„œ ๋ฐฐ์šธ ์ˆ˜ ์žˆ๋Š” ๊ฐ€์žฅ ์ข‹์€ ์žฅ์†Œ์ž…๋‹ˆ๋‹ค.

License

CC 4.0

ยฉ Denys Dovhan