배시 (유닉스 셸)

**배시**(Bash, "본 어겐 셸/Bourne Again SHell"의 약자)는 유닉스 계열 운영체제를 위해 개발된 상호작용형 명령줄 인터프리터이자 스크립트 언어다. 1989년 GNU 프로젝트를 위해 브라이언 폭스가 제작했으며, 본 셸() 및 기타 독점 유닉스 셸들을 대체하기 위한 완전한 자유 소프트웨어로 설계되었고, 자유 소프트웨어 재단의 지원을 받는다. 배시는 널리 채택되어 수많은 리눅스 배포판에서 기본 로그인 셸로 흔히 사용된다. 또한 셸 스크립트라고 불리는 파일로부터 명령어를 실행하는 기능을 지원하여 자동화를 용이하게 한다.

배시의 명령어 구문은 본 셸 구문의 상위 집합이며, 본 셸 구문의 모든 기본 기능을 복제했다. 결과적으로 배시는 대부분의 본 셸 스크립트를 수정 없이 실행할 수 있다. 그 외의 몇몇 아이디어들은 C 셸, 그 후속인 Tcsh, 그리고 콘셸에서 가져왔다. 배시는 거의 모든 현대 운영체제에서 사용할 수 있어 다양한 컴퓨팅 환경에서 다재다능한 도구로 쓰인다.

## 정의

### ASCII, 문자열과 숫자


```console
$ printf '<newline>:  <%b>\n' $'\n'
<newline>:  <
>
$ printf '<tab>:      <%b>\n' $'\t'
<tab>:      <	>
$ printf '<space>:    <%s>\n' " "
<space>:    < >
$ printf '<NUL>:      <%b>\n' $'\0'
<NUL>:      <>
```


일련의 문자들을 "문자열" 또는 "문자열 리터럴"이라고 부른다. 유닉스 계열 운영체제에서는 널 문자와 슬래시  같은 몇몇 문자를 제외한 출력 가능하거나 출력 불가능한 모든 문자를 파일 이름에 사용할 수 있다. 또한 모든 문자열은 대소문자를 구분한다.

배시는 다른 많은 프로그래밍 언어와 마찬가지로 0부터 시작하는 번호 매기기를 사용한다.

### Control+키 조합

Control+키 기능은 GNU readline에 의해 제공되며 상호작용 모드에서만 사용할 수 있다. 특정 키 누름 조합을 통해 사용자는 탭 완성 기능을 사용하거나 명령어 기록을 검색하는 등의 배시 조작이 가능하다.

*  – 탭 완성 활성화
*  – 명령어 기록에서 위로(즉, 이전으로) 스크롤
*  – 명령어 기록에서 아래로(즉, 다음으로) 스크롤
*  – 명령어 기록 검색

일부 키 조합은 사용자가 터미널 창 내에서 커서를 이동하거나 에뮬레이터 프로그램을 제어하기 위해 단말 에뮬레이터를 조작할 수 있게 해준다. 기본적으로 배시의 이러한 키 조합은 이맥스의 것을 반영한다.

제어 코드를 위한 기본 키 바인딩은 다음과 같다:

*  – 커서를 오른쪽으로 한 글자 이동
*  – 커서를 왼쪽으로 한 글자 이동
*  – 커서를 오른쪽으로 한 단어 이동
*  – 커서를 왼쪽으로 한 단어 이동
*  – 커서를 현재 명령줄의 시작 부분으로 이동
*  – 현재 명령어를 취소하고 새로운 프롬프트를 표시
*  – 현재 배시 인스턴스를 종료하며, 경우에 따라 터미널 에뮬레이터도 종료
*  – 커서를 현재 명령줄의 끝 부분으로 이동
*  – 터미널을 깨움; 이후 버퍼링된 키 입력이 처리됨
*  – 터미널을 대기 상태로 전환
*  – 커서 왼쪽의 한 단어를 제거
*  – 포그라운드 프로세스를 정지

Vi 키 바인딩도 사용할 수 있으며, 를 실행하여 활성화할 수 있다.

### 구문
배시가 전체 명령줄을 읽을 때, 완성된 문자열은 토큰들로 분해된다. "토큰"은 메타문자를 사용하여 식별되고 서로 분리된다.

배시 5.3 기준으로, 10개의 메타문자는 공백, 탭, 개행 문자 및 다음 문자들이다: 

"Blanks"는 순수하게 인용되지 않은 메타문자로 구성되며, "operators"는 각각 적어도 하나의 인용되지 않은 메타문자를 포함하고, "words"는 인용되지 않은 메타문자를 포함할 수 없다.

실제로 배시는 전체 명령어 문자열을 메타문자를 포함하는 토큰 또는 토큰 그룹과, 메타문자를 포함하지 않는 토큰 또는 토큰 그룹("words"라고 불림)으로 분해한다. 거기서부터 단어들을 명령어 이름, 변수 할당문 등 더 구체적이고 의미 있는 조각들로 더 분해한다.

두 가지 공백(Blanks)은 스페이스와 탭이다.

#### 연산자

제어 연산자(Control operators)는 제어 기능을 수행한다. 개행 문자이거나 다음 중 하나일 수 있다: `||`, `&&`, `&`, `;`, `;;`, `;&`, `;;&`, `|`, `|&`, `(`, 또는 `)`.

리다이렉션 연산자(Redirection operators)는 입력 또는 출력 스트림을 재지정한다. 여기에는 `&lt;`, `&gt;`, `&amp;&gt;`, `&lt;&lt;`, `&lt;&lt;&lt;` 등이 포함된다.

#### 단어
단어(word)는 셸에 의해 단일 단위로 취급되는 (메타문자가 아닌) 문자들의 시퀀스다. 예약어(reserved word)는 셸에 특별한 의미를 갖는 단어의 종류다.
이름(name)은 예약어와는 구별되는 단어의 종류다. 이름은 오직 문자, 밑줄, 숫자로만 구성되며, 문자나 밑줄로 시작해야 하고 숫자로 시작할 수 없다. 식별자(identifiers)라고도 불리는 이름은 변수와 함수의 이름을 짓는 데 사용될 수 있다.

문자 또는 단어일 수 있는 22개의 "예약어" 중 16개는 다음과 같다:


```bash
'!' '[[' '{' ']]' '}' case in esac for do done if then elif else fi ...
```


이름은 오직 `ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_` 문자들만 포함할 수 있다.

다음 전체 명령어 문자열의 예에서, 메타문자 위에는 쉼표 가, 예약어 아래에는 캐럿 이, 그리고 다른 토큰 아래에는 백틱 이 표시되어 있다.


```console
$ #,  ,    ,   ,,    ,       ,,  ,
$   if echo foo; then bar=abc; fi
$ # ^^ ```` ```  ^^^^ ```````  ^^
```


### 서브셸

"서브셸"(subshell)은 현재 셸 인스턴스에 의해 초기화된 셸의 추가 인스턴스다. "부모" 셸이 서브셸 또는 "자식" 셸을 생성할 때, 부모의 환경 정보에 대한 정확한 복사본이 다시 생성되어 서브셸의 환경이 된다.

배시의 비산술 문맥에서는 전체 명령어 문자열을 단일 괄호로 묶어 서브셸 사용을 강제할 수 있다.


```console
$ echo foo
foo
$ ( echo foo )
foo
$
```


이 간단한 사례에서는 앞의 두 명령어가 동일하지만, 서브셸의 사용은 특정 예상치 못한 부작용을 일으킬 수 있다. 서브셸의 초기화를 유발할 수 있는 다양한 형태의 구문들이 존재한다.

### 확장

### 데이터 구조

배시는 데이터 구조로 변수와 배열을 제공하며, 각각 다양한 종류가 존재하지만 C나 자바와 같은 다른 언어에 비하면 데이터 구조가 상대적으로 단순하다. 모든 데이터는 메모리에 문자열로 저장된다.

단어의 시작 부분에 달러 기호를 붙이는 것은 그 단어가 변수 또는 배열의 이름임을 나타낸다. 달러/변수 이름 구문을 큰따옴표로 감싸는 것이 항상 권장된다. 이 관행은 매개변수가 보유한 값이 원치 않는 부작용을 일으키는 것을 방지한다.

변수 이름을 중괄호 로 감싸는 것은 가독성과 변수 및 배열 간의 일관성을 위해 권장된다. 변수를 쓸 때 중괄호는 선택 사항이지만 대괄호를 쓰는 것은 구문 오류가 된다. 매개변수 이름은 항상 등호의 왼쪽에 오고 값은 항상 오른쪽에 온다.

#### 변수

변수는 `name=value` 구문을 사용하여 할당된다.

변수를 사용하려면 `$name` 또는 `${name}` 구문을 사용하며, 이는 변수에 할당된 값으로 확장된다.

후자의 구문은 원치 않는 부작용을 방지하기 위해 특정 이름에 반드시 사용해야 한다. 예를 들어 `$10`은 `${1}0`으로 파싱되므로, `${10}`을 사용하는 것이 의도한 대로 파싱됨을 의미한다.

대개 배시 스크립트로 전달되는 위치 매개변수(Positional parameters)는 $0부터 시작하는 숫자가 붙은 변수로 표시된다. 특수 매개변수(Special parameters)는 구두점 문자로 표시된다. 예를 들어, 는 첫 번째부터 마지막 위치 매개변수까지의 목록으로 확장된다.

환경 변수는 모두 대문자로 표시된다. 환경 변수에는  같은 유닉스 변수와  같은 본 셸 변수가 포함된다. 스크립팅 변수는 모두 소문자 또는 카멜 케이스(CamelCase)로 표시된다. 이는 관례일 뿐이며, 어떤 변수든  명령어로 전달하여 환경 변수로 만들 수 있다.

#### 배열
배열은 여러 값을 보유하는 데이터 구조다. 배열은 변수 이름 끝과 중괄호 안에 한 쌍의 대괄호를 둔다. 배열을 쓸 때는 중괄호와 대괄호가 필수적이다.

배열은 `name=( 요소1 요소2 ... )` 구문을 사용하여 할당된다. 사용 사례에 따라 , , 또는 를 사용하여 확장한다.

각 매개변수 종류는 특정 명명 규칙에 의해 구별된다.

배시 4.0부터는 연관 배열도 지원한다.

이 문서에서 이 섹션의 변수 예시로는 , ,  등이 있다.

### 실행

지정된 프로그램의 "실행"은 사용자(또는 다른 프로그램)가 운영체제에 해당 프로그램에 포함된 지침에 따라 행동하도록 요청할 때 발생한다.

기본적으로 배시는 사용자 코드를 한 번에 한 줄씩 읽고, 개행 문자나 세미콜론 을 현재 명령어의 끝으로 해석하며, 명령어를 순차적으로 실행한다. 상호작용형 명령어가 단말 에뮬레이터의 너비를 넘어서는 경우, 보통 계속 타이핑이 가능하며 명령어는 다음 줄로 넘어간다(wrap). 명령어를 개행 문자 너머 다음 줄로 연장하려면, 첫 번째 줄의 마지막 문자가 이스케이프되지 않은 백슬래시 여야 하며, 이는 "줄 연속"(line continuation) 신호가 된다. 배시는 항상 한 전체 명령줄의 파싱과 실행을 마친 후에 다음 명령줄의 파싱을 시작한다.


```console
$ foo=aa bar=bb quux=cc zork=dd; set -o xtrace
$ : "${foo}"; : "${bar}"
+ : aa
+ : bb
$ : "${quux}" \
> : "${zork}"
+ : cc : dd
$
```


명령줄의 첫 번째 단어는 "명령어 위치"(command position)라고 알려져 있다. 유닉스 관례에 따라 명령줄의 첫 번째 단어는 항상 일종의 명령어이며, 명령줄 문자열의 나머지 단어들은 해당 명령어의 옵션, 옵션의 인자, 또는 명령어가 작동할 대상인 입력값들이다. "옵션"은 "플래그"(flags), "스위치"(switches), 또는 더 공식적으로는 "연산자"(operators)라고도 불린다. 배시가 실행할 명령어를 찾을 때 검색하는 디렉터리들은  변수에 나열된 것들과 현재 작업 디렉터리다.


```console
$ # [COMMAND POSITION] [OPTION] [ARGUMENTS]
$ # ,--^   ,------------^   ,----^
$ declare -p USER BASH_VERSION
declare -x USER="liveuser"
declare -- BASH_VERSION="5.2.37(1)-release"
$
```


### 사용자와 PS1

사용자 계정은 사람 또는 프로그램 사용자를 위해 생성될 수 있다. 유닉스 계열 운영체제에는 "권한이 있는"(privileged) 사용자와 "일반"(regular) 사용자의 두 종류가 있다. 루트(root)나 운영체제 커널과 같은 권한 있는 사용자는 시스템에서 무엇이든 할 수 있다. 권한이 없는 사용자는 다양한 방식으로 제한된다.

상호작용형 셸 세션이 사용자 입력을 기다릴 때, 기본적으로 화면에 특정 문자열을 출력한다. 배시에서 이 대기 문자열의 값은 셸 변수 에 보관된다. 일반 사용자의 경우 의 공통 기본값은 달러 기호 다. 슈퍼유저의 경우 공통 기본값은 해시태그()다.


```console
$ sudo --login --user root
[sudo] password for liveuser:
# vim /home/liveuser/names.txt
# exit
$ grep -e bob ./names.txt
grep: ./names.txt: Permission denied
```


## 모드

### 프로그래밍 패러다임

배시는 C로 작성되었다. 좋은 스타일과 신중한 설계를 통해 모듈식 스타일을 근사할 수 있다. 배시는 종종 명령형 프로그래밍 또는 절차적 프로그래밍 스타일로 사용된다.

### 상호작용 및 비상호작용 모드

명령어 프로세서로서 배시는 상호작용 또는 비상호작용의 두 가지 모드로 작동할 수 있다. 상호작용 모드에서 명령어는 대개 단말 에뮬레이터로부터 읽어 들인다. 자동화를 용이하게 하는 비상호작용 모드에서는 명령어는 대개 오늘날 셸 스크립트라고 알려진 이름 있는 파일로부터 읽어 들인다. 명령줄 인터페이스(CLI)에서 독립형 명령어로 실행될 때, 기본적으로 배시는 상호작용 모드에서 새 셸을 연다.

### 스크립트

셸 스크립트는 코드(종종 명령어)를 포함하는 텍스트 파일로, 추가적인 사용자 상호작용 없이 비상호작용 모드의 일괄 처리에서 특정 인터프리터에 의해 읽히고 실행되도록 의도된 것이다. 해석되는 스크립트는 소스 코드를 컴파일할 필요가 없는 컴퓨터 프로그램이며, 모든 관련 소스 코드가 스크립트 내에 포함되어 있다. 스크립트 인터프리터 역할을 할 수 있는 프로그램은 펄, AWK 등 많이 있다. 해석되는 스크립트는 유닉스 셸용으로 가장 자주 작성된다.

(실행 가능한) 셸 스크립트의 첫 번째 줄의 처음 두 문자는 셔뱅이라고 불리는 것으로 시작한다. 문자 그대로 해시태그()와 느낌표()가 나란히 붙어 있는 형태다.


```console
$ cat ./example.sh
#! /bin/env bash
echo foo
exit

$
```


스크립트가 명령줄에서 독립형 프로그램으로 사용자에 의해 실행되도록 의도된 경우, 이를 "실행 파일"이라고 부른다. 관례에 따라 실행 가능한 유닉스 셸 스크립트의 파일 이름은 접미사 로 식별된다. "실행" 비트는  유틸리티를 사용하여 셸 스크립트에서 활성화할 수 있다.


```console
$ ls -l ./example.sh
-rw-r--r--.1 liveuser liveuser 32 Aug  3 22:33 example.sh
$ ./example.sh
bash: ./example.sh: Permission denied
$ chmod 0744 ./example.sh
$ ls -l ./example.sh
-rwxr--r--.1 liveuser liveuser 32 Aug  3 22:33 example.sh
$ ./example.sh
foo
$
```


### 내장 명령어

 또는 동의어인  명령어를 통해 배시는 이름으로 지정된 텍스트 파일로부터 셸 명령어를 읽고 실행한다.

### 로그인 및 비로그인 셸

배시는  옵션을 통해 상호작용 및 비상호작용 모드 모두에서 로그인 셸 또는 "세션 리더"로 실행될 수 있다. "로그인"에는 사용자 인증이 필요하다. 이러한 이유로 사용자 세션당 하나의 로그인 셸만 존재한다. GNU/리눅스에서 사용자의 로그인 셸은 /etc/passwd 파일에 식별되어 있다.


```console
$ awk -F ':' '$1 ~ /root/' /etc/passwd
root:x:0:0:Super User:/root:/bin/bash
```


사람 사용자가 로그인 세션을 시작할 때, 이 절차는 종종 그래픽 사용자 인터페이스(GUI)에서 발생한다. 사용자가 단말 에뮬레이터를 열 때, 에뮬레이터는 사용자의 로그인 셸의 비로그인 인스턴스를 실행한다.

단말 에뮬레이터 내에서 셸 세션을 로그아웃하는 것은  명령어를 사용하거나, 배시의 기본값인 를 눌러 수행할 수 있다.

### 시작  파일

배시가 시작될 때, 를 사용하여 다양한 도트 파일(아래 목록 참조)의 명령어들을 실행한다.
이 도트 파일들은 셸 스크립트와 달리 일반적으로 실행 권한이 활성화되어 있지 않으며 셔뱅도 없다. 기본적으로 배시는 다음에 따라 다소 다른 파일 세트를 다른 순서로 읽어 들인다:
* 배시가 호출되는 방식: 상호작용, 비상호작용, 라는 이름으로 호출됨
* 사용된 옵션: , , , 
* 정의된 환경 변수: , , 그리고
* 존재하는 파일:
** 
** 
** 
** 
** , 그리고
** 기타  등.

물론 모든 시작 파일은 다른 파일의 명령어를 실행할 수도 있다. 시작 파일은 셸 동작, 단말 에뮬레이터, X 윈도 시스템, 창 관리자 등에 영향을 줄 수 있다.

### POSIX 모드

POSIX IEEE 1003.1 표준은 모든 셸 시스템 애플리케이션(배시, dash, zsh 등)이 준수할 수 있는 공통 정의 세트를 규정한다. POSIX 지침에 맞춰 작성된 모든 셸 사용자 스크립트()는 POSIX 사양을 구현한 모든 셸 시스템 애플리케이션에서 실행 가능해야 한다. 결과적으로 POSIX 호환 스크립트는 POSIX 표준을 구현하는 모든 유닉스 또는 유닉스 계열 운영체제(리눅스, OpenBSD, 오라클 리눅스, HP-UX 등)에서 수정 없이 성공적으로 실행될 것으로 기대할 수 있다. 이러한 스크립트들은 있는 그대로 "이식성"이 있다고 간주된다. 셸과 명령줄 유틸리티에 적용되는 POSIX 부분은 단말기와 단말 에뮬레이터가 이식성 있게 작동하기 위해 어떻게 기능해야 하는지를 추가로 규정하는 더 큰 POSIX 표준 그룹의 하위 집합이다.

배시가 POSIX 모드로 작동할 때는 사용할 수 있는 기능이 적어지지만, 결과 코드는 더 다양한 운영체제에서 실행될 수 있다.

상호작용형 셸의 초기화 시 POSIX 모드를 활성화하려면 배시를 ,  또는 로 실행하면 된다. 스크립트가 POSIX 모드에서 초기화되도록 하려면 셔뱅  또는 이식성이 떨어지는 를 사용한다. 배시 인스턴스가 POSIX 모드에서 작동 중일 때 환경 변수 가 정의되며, 환경 변수 의 값에  문자열이 포함된다.


```console
$ declare -p POSIXLY_CORRECT
bash: declare: POSIXLY_CORRECT: not found
$ sh
$ declare -p POSIXLY_CORRECT
declare -- POSIXLY_CORRECT="y"
$
```


배시에서 사용할 수 있지만 POSIX에서 규정하지 않은 기능 목록은 상당히 방대하다. 다음은 그중 일부다:
* 위치 매개변수 배열 를 제외한 모든 배열은 POSIX가 아님
* 이중 대괄호 확장 테스트 구문 은 POSIX가 아님
**  및 는 POSIX임
* 이중 괄호 산술 평가 구문 중 하나인 은 POSIX가 아님
** 은 POSIX임
* 중괄호 확장 `kernel{,-headers}`은 POSIX가 아님
* 매개변수의 동적 스코핑과  내장 명령어는 POSIX가 아님
* 프로세스 치환 , 은 POSIX가 아님
* 매개변수 확장 시의 특정 문자열 조작 연산은 POSIX가 아님
* 대부분의 배시 내장 명령어는 POSIX가 아님
**  명령어는 POSIX인 본 셸 특수 내장 명령어 목록을 출력함
```console
$ enable -s | wc --lines
16
$ enable | wc --lines
61
```

**  내장 명령어 자체는 POSIX가 아님
** 배시의 비 POSIX 모드에서 과  내장 명령어는 동의어임
*** 하지만  (즉, '점') 내장 명령어는 POSIX임
***  내장 명령어는 POSIX가 아님
*  및  셸 변수는 POSIX가 아님

현대 유닉스 계열 운영체제에서 사용할 수 있고 POSIX에서도 규정된 시스템 명령어들은 POSIX 환경에서 옵션 플래그가 적거나 관련 환경 변수가 적을 수 있다. 대부분(예: )은 배시 내장 명령어가 아니라 , ,  또는  디렉터리에 있는 독립형 프로그램(리눅스에서는 일반적으로 GNU 코어 유틸리티 또는 비지박스에 의해 제공됨)이다.

이러한 차이점들 때문에 현대(버전 5) 배시 셸 스크립트가 본 셸이나 구형 콘셸 인터프리터에서 "있는 그대로" 실행되는 경우는 드물다. GNU/리눅스가 널리 보급됨에 따라 이식성을 고려한 스크립팅은 덜 일반적이 되고 있다.

배시에서는 유효한 구문이지만 POSIX에서는 규정되지 않은 코드를 "bashism"이라고 부른다.  프로그램을 사용하여 스크립트가 데비안 리눅스에서 이식성 오류 없이 실행될 수 있는지 확인할 수 있다. Vidar Holen의 는 하스켈로 작성된 또 다른 정적 린터로, 배시, dash, ksh, 본 셸 중 어느 하나 또는 전부에 대한 호환성을 위해 스크립트 구문을 분석할 수 있다.

각 셸의 구문 요구 사항은 조금씩 다르다. 예를 들어 데비안의 정책은 스크립트에서 일부 확장 기능(dash 셸에 있는 기능 등)을 허용하는 반면, Autoconf의 처럼 POSIX 이전의 본 셸 지원을 의도하는 스크립트는 사용할 수 있는 기능이 훨씬 더 제한적이다.

### 기타 모드

#### 제한 모드

제한된 셸은 표준 셸보다 더 엄격하게 통제된 환경을 설정하는 데 사용된다. 제한된 셸은 다음을 포함한 수많은 작업이 허용되지 않거나 수행되지 않는다는 점을 제외하면 배시와 동일하게 작동한다:

*  내장 명령어로 디렉터리 변경.
* , , , , 또는  변수의 값 설정 또는 해제.
* CLI에서 슬래시를 포함하는 명령어 이름 지정.
* , , 또는  명령어의 인자로 절대 경로명 사용.
*  또는 로 경로 검색 지정.
* 시작 시 셸 환경으로부터 함수 정의 가져오기 및  값 파싱.
* , , , , , 및  리다이렉션 연산자를 사용하여 출력 재지정.
*  내장 명령어를 사용하여 셸을 다른 명령어로 교체.
* 셸 내장 명령어 수정.

일반적으로 제한 모드가 활성화되면 이를 비활성화할 수 없다. 이러한 제한은 시작 파일을 읽은 후에 적용되며 셸 스크립트에는 적용되지 않는다. 제한 모드는 거의 사용되지 않는다.

#### 권한 모드

배시에서 "권한 모드"(privileged mode)는 SVR4.2 유닉스 시스템 V 셸(1992년경)에서 상속된 거의 사용되지 않는 옵션이다. 로 활성화하고 로 비활성화할 수 있다. 권한 모드가 활성화되면  셸 변수에 "privileged" 문자열이 포함된다.

#### 확장 디버깅 모드

호출 시 를 사용하거나 상호작용 또는 비상호작용 모드 중에 를 통해 활성화된다. 이는 라고 불리는 별도의 프로그램을 사용한다. 는 POSIX 모드에서는 사용할 수 없다. 자세한 내용은 문서를 참조하라.  섹션도 참조하라.

#### 호환성 모드

## 관찰 가능성

### 옵션

가 활성화되면 간단한 디버깅 내용이 터미널에 출력된다.  또는 로 활성화하고, ,  또는 로 비활성화할 수 있다. 이러한 옵션들은 명령줄이나 셔뱅에서도 허용된다:  등.


```console
$ bash -x
$ echo $((  2 + 2  ))
+ echo 4
4
$ set -- 1 2 3
$ printf '<%s>\n' "$@"
+ printf '<%s>\n' 1 2 3
<1>
<2>
<3>
$
```


 셸 설정은 POSIX에 의해 규정되어 있다.  섹션도 참조하라.

### 옵션

verbose 옵션은 문자열이 읽힐 때, 그리고 확장이 수행되기 전에 터미널에 문자열을 출력한다. 거의 사용되지 않는다.

### 주석

주석은 정보를 명확히 하거나, 스크립트 작성자의 의도나 맥락을 잘 모르는 다른 사람에게 스크립트 또는 소스 파일을 설명하는 가치 있는 방법이 될 수 있다.

배시의 표준 주석은 해시 문자 로 표시된다. 해시 오른쪽부터 줄 끝까지의 모든 텍스트는 무시된다. 인라인 주석이 허용되지만, 해시 주석은 디버깅 중에 출력되지 않는다. 를 참조하라.

콜론 문자 로 표시되는 주석은 톰프슨 셸에서 유래했다. 콜론  내장 명령어의 오른쪽에 있는 모든 인자는 무시된다. 인라인 주석은 불가능하지만, 콜론 주석은 디버깅 중에 출력되며 모든 매개변수는 확장된 상태가 된다.

:
```console
$ # foo 정의
$ foo=bar # 인라인 해시 주석은 명령어와 같은 줄에 위치함
$ set -x
$ # 일반 주석 (출력 없음)
$ : "${foo}"
+ : bar
$
```


### 종료 코드

배시가 명령어를 실행할 때, 프로그램이 실행을 중단한 방식에 대한 통찰을 제공할 수 있는 "반환 코드"라고도 불리는 종료 상태 코드가 생성된다. 가장 최근에 캡처된 종료 코드의 값은 셸 매개변수 '물음표' 에 보관된다. 비산술 문맥(즉, 대부분의 경우)에서 "참"의 수치적 또는 "불" 값은 0이고, "거짓"의 값은 1이다.

시스템 명령어가 실행되었을 때, 종료 상태의 의도된 의미는 대개 해당 man page에서 찾을 수 있다. 보통 0은 성공을 나타내고 0이 아닌 종료 상태는 일종의 실패 조건 또는 부분적 성공을 나타낸다. 은 0, 1, 2라는 세 가지 의미 있는 종료 코드를 갖는 잘 알려진 명령어다.

배시 내의 산술 문맥에서는 수치적 진릿값이 반대다: "참"은 1이고 "거짓"은 0이다. 산술 문맥은 대개  또는  구문으로 식별할 수 있다. 산술 문장이 정수 0으로 평가되면 문장은 "참"으로 간주되고 종료 코드는 1이 된다. 문장이 0 이외의 숫자로 평가되면 산술 문장은 "거짓"이고 종료 코드는 0이 된다.

모든 리눅스/유닉스 명령어가 0과 1 이상의 의미 있는 종료 코드를 제공하는 것은 아니며, 리눅스에서 종료 코드 정의에 대한 표준 시스템은 없다.

:
```console
$ true; echo "$?" # 종료 코드는 "참"을 의미함
0
$ false; echo "$?"; echo # 종료 코드는 "거짓"을 의미함
1
$
$ bash -c 'exit 99'; printf 'exit-code: %d\n\n' "$?"
exit-code: 99
$
$ ((  1 - 1  )); printf '%d\n' "$?" # 이 종료 코드는 "참"을 의미함
1
$ ((  1 + 1  )); printf '%d\n' "$?" # ...그리고 이 종료 코드는 "거짓"을 의미함
0
```


### 작업 제어

배시 셸에는 명령어 실행을 위한 두 가지 모드가 있다: 배치(비동기) 및 동시(동기). 배치 모드(즉, 순차적)로 명령어를 실행하려면 문자 로 구분하거나 별도의 줄에 작성해야 한다:

:
```console
$ 명령어1; 명령어2
$ 명령어3
$
```


이 예시에서 이 끝나면 가 실행되고, 가 완료되면 이 실행된다. 의 백그라운드 실행은 실행 명령어 끝에 기호 를 사용하여 수행할 수 있으며, 프로세스는 백그라운드에서 실행되는 동안 즉시 셸로 제어를 반환하여 계속해서 명령어를 실행할 수 있게 한다.

:
```console
$ 명령어1 &
$
```


또는 과 를 동시에 실행하려면 배시 셸에서 다음과 같은 방식으로 실행해야 한다:

:
```console
$ 명령어1 & 명령어2
$
```


이 경우 은 백그라운드에서 실행되어(기호 ) 셸에 즉시 제어를 반환하고, 셸은 포그라운드에서 를 실행한다. 프로세스가 포그라운드에서 실행되는 동안 를 타이핑하여 프로세스를 정지시키고 배시로 제어를 반환할 수 있다. 백그라운드에 있거나 정지된 모든 프로세스의 목록은 를 실행하여 얻을 수 있다:

:
```console
$ jobs
[1]-  Running                  명령어1 &
$
```


출력에서 대괄호 안의 숫자는 작업 ID(job id)를 나타낸다. 더하기 기호는  및 의 기본 프로세스를 나타낸다. "Running"과 "Stopped" 텍스트는 프로세스 상태를 나타낸다. 마지막 문자열은 프로세스를 시작한 명령어다.

다양한 명령어를 사용하여 프로세스의 상태를 변경할 수 있다.  명령어는 프로세스를 포그라운드로 가져오고, 는 정지된 프로세스를 백그라운드에서 실행되도록 설정한다. 와 는 작동할 프로세스를 지정하기 위해 작업 ID를 첫 번째 인자로 받을 수 있다. 작업 ID가 없으면  출력에서 더하기 기호로 표시된 기본 프로세스를 사용한다.  명령어는 신호를 보내 프로세스를 조기에 종료하는 데 사용될 수 있다. 작업 ID는 퍼센트 기호 뒤에 지정해야 한다:

:
```console
$ sleep 100 &
[1] 4904
$ kill %1
$ jobs
[1]+  Terminated                    sleep 100
$
```


"모니터 모드"라고도 알려진 작업 제어는 상호작용형 셸에서 기본적으로 활성화되어 있으며, 로 비활성화할 수 있다.

### 신호

신호 전달은 프로세스 간 통신(IPC)의 한 수단이다. 때때로 명령줄 프로세스가 실행 중에 멈춘 것처럼 보일 수 있다. 이런 경우 어떤 프로세스가 차단되었는지 식별하고 문제가 되는 프로세스를 수동으로 종료해야 할 수도 있다.

상호작용형 터미널에서는 대개 를 눌러 현재 포그라운드 프로세스를 종료하고 사용자 프롬프트로 제어를 반환하거나, 를 눌러 정지시키는 것으로 충분하다. 가끔 프로세스를 취소하려는 시도가 무응답일 때 프로세스를 정지시키려는 시도는 성공하기도 한다. 다른 경우에는 IPC 신호를 보내기 위해  프로그램을 사용해야 할 수도 있다. 이 예제에서는 두 번째 터미널 화면에서  명령어를 사용하여 PID 4331 프로세스를 종료한다.

:
```console
$ tty # 터미널 1
/dev/pts/0
$ whoami
liveuser
$ sleep 1000 # 명령어가 멈춤
```


:
```console
$ tty # 터미널 2
/dev/pts/1
$ whoami
liveuser
$ ps aux | grep -e sleep -e PID
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START    TIME COMMAND
liveuser    4331  0.0  0.0 230336  2312 pts/1    S+   11:19    0:00 sleep 1000
liveuser    4333  0.0  0.0 231248  2516 pts/0    S+   11:19    0:00 grep --color=auto -e sleep -e PID
$ kill 4331
$ ps aux | grep -e sleep -e PID # sleep 프로세스가 종료됨
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START    TIME COMMAND
liveuser    4333  0.0  0.0 231248  2516 pts/0    S+   11:19    0:00 grep --color=auto -e sleep -e PID
$
```


:
```console
$ tty # 다시 터미널 1
/dev/pts/0
$ whoami
liveuser
$ sleep 1000
Terminated
$
```


유닉스 계열 운영체제에서 사용자는 커널에 자신이 소유한 프로세스로 신호를 보내도록 지시할 수 있다. 일반 사용자는 권한이 있는 프로세스에 신호를 보낼 수 없다. 신호는  내장 명령어 또는 동일한 이름의 시스템 바이너리를 사용하여 프로세스에 전달될 수 있다.

:
```console
$ whoami
liveuser
$ ps aux | awk '$2 ~ /\<1\>/' # 커널 프로세스인 1번 프로세스의 정보를 봄
root           1  0.0  0.2  37140 20440 ?        Ss   04:44    0:18 /usr/lib/systemd/systemd --switched-root --system --deserialize=53 rhgb
$ kill -s SIGKILL 1
bash: kill: (1) - Operation not permitted
$ type -a kill
kill is a shell builtin
kill is /usr/bin/kill
$ /usr/bin/kill -s SIGKILL 1
kill: sending signal to 1 failed: Operation not permitted
$
```


가장 흔히 사용되는 신호는 kill -L | head -n 4로 확인할 수 있다. 각 IPC 신호는 신호 번호와 연관되어 있지만, 종료 코드와 신호 코드는 서로 다른 것이다. 프로세스에 IPC 신호 9("KILL" 신호)를 보내면 거의 확실히 프로세스가 즉시 종료되지만, 그렇다고 해서 프로세스가 종료 코드 9를 반환하게 될 가능성은 매우 낮다.

배시의 내장 kill은 기본적으로 TERM("종료") 신호를 보낸다. 명령줄 유틸리티가 SIGTERM에 응답하여 정상적으로 시스템을 닫고 종료하는 것은 흔한 일이다. (TERM과 SIGTERM은 동일하며, 모든 신호 이름의 SIG- 접두사는 생략할 수 있다.) 배시에서 Ctrl-c 키 시퀀스는 포그라운드 프로세스에 SIGINT(인터럽트 신호)를 보낸다. Ctrl-z 키 시퀀스는 SIGSTOP(정지 신호)를 보낸다. 프로세스가 SIGKILL을 받으면 프로세스는 즉시 비정상적으로 종료된다. SIGKILL은 최후의 수단으로만 사용하는 것이 권장된다. SIGKILL 신호는 차단하거나 처리할 수 없다.

프로세스는 자신이 받는 IPC 신호를 "포착"(catch)하고 "처리"(handle)할 수 있다. 사용자는 kill 내장 명령어를 사용하여 다른 프로세스에 IPC 신호를 "보낼" 수 있다. 해당 대상 프로세스는 특정 신호를 받을 때(또는 포착할 때) 어떻게 응답할지에 대한 메커니즘이나 계획을 미리 설정해 둘 수 있다. 대상 프로그램이 응답하는 방식은 프로그램이 신호 수신을 어떻게 "처리"하느냐로 지칭된다. man page를 보면 일부 시스템 명령어들이 SIGHUP를 받을 때 터미널에 특정 정보를 출력하는 것을 볼 수 있다: 예를 들어  명령어가 그러하다.

기본적으로 배시 셸 스크립트는 자신에게 전송된 모든 IPC 신호를 받고 응답하지만, 배시 스크립트는  내장 명령어를 사용하여 신호를 포착하고 처리할 수 있다.

:
```console
$ cat ./trap-example.sh
#! /usr/bin/env bash
trap umask EXIT
echo bar
exit 0
$ chmod 0700 trap-example.sh
$ ./trap-example.sh
bar
0077
$
```


오직 배시 내에서 GNU 확장으로만 사용 가능한 몇몇 신호들이 있다: , , , . 이 신호들은 디버깅에 유용할 수 있으며 셸 내장 명령어에 의해서만 전송되고 처리될 수 있다.  섹션도 참조하라.

### 매개변수의 값

의 구현 방식은 매우 다양하다. 어떤 것은  옵션이 있고 어떤 것은 없다. 옵션 목록은 구현마다 동일하지 않지만, 와 는 모두 POSIX에 의해 규정되어 있다. 스크립트 작성자가 변수에 포함된 문자열의 정확한 값을 알고 싶다면 가장 일관된 방법은 를 사용하는 것이다.

문자(숫자 포함)를 포함하는 모든 문자열에 대해 형식 지정자는 다.

:
```console
$ foo=abc bar=123
$ printf '<%s>\n' "${foo}" "${bar}"
<abc>
<123>
$
```


숫자 전용의 경우 형식 지정자는 다.

:
```console
$ printf '<%d>\n' "${foo}" "${bar}"
bash: printf: abc: invalid number
<0>
<123>
$
```


를 사용하면 스크립트 작성자가 형식 문자열에 개행 문자를 포함하지 않는 한 출력에 개행 문자가 절대 포함되지 않는다. 아래 예제처럼 형식 문자열에서 개행 문자가 생략된 경우, PS1의 값은 이전 명령어의 출력과 같은 줄에 출력된다.

:
```console
$ printf '<%s>' "${foo}" "${bar}"
<abc><123>$
```


또 다른 일관된 방법은 를 사용하는 것이다. 의 출력은 입력으로 재사용할 수 있다. 그러나 모든 변수와 매개변수를 로 출력할 수 있는 것은 아니다. 예를 들어 특수 매개변수의 값은 출력할 수 없다. 특수 매개변수 해시태그 는 현재 정의된 위치 매개변수가 몇 개인지 보고한다.

:
```console
$ declare -p foo bar
declare -- foo="abc"
declare -- bar="123"
$ declare -p "$#"
bash: declare: 0: not found
$
```


상호작용형 셸의 전체 입력 문자열에 대해...

:
```console
$ declare -p #
```


...해시태그는 배시에 의해 인라인 주석으로 해석될 것이다. 주석과 그 오른쪽의 모든 텍스트가 제거된 상태에서 배시가 실행할 명령어는 가 된다. 이 명령어는 에 따르면 "각 이름의 값과 속성을 표시"하며, "이름이 주어지지 않으면 모든 변수의 속성과 값을 표시"하므로 100줄 이상의 출력이 나올 수 있다.

반면 는 변수의 속성을 표시할 수 없다.  섹션도 참조하라.

:
```console
$ readonly foo
$ declare -p foo
declare -r foo="abc"
$ printf '<%s>' "${foo}"
<abc>
$
```


### 환경

구성 가능한 실행 환경:
*  및  같은 셸 및 세션 시작 파일(도트 파일);
* 셸 동작을 변경하는 설정( 내장 명령어) 및 셸 옵션( 내장 명령어).

셸 및 세션 시작 파일(일명 "도트 파일")

배시가 시작될 때 다양한 도트 파일의 명령어를 실행한다. 배시 셸 스크립트와 달리 도트 파일은 일반적으로 실행 권한이 없으며  같은 인터프리터 지시어도 없다.

* 레거시 호환 배시 시작 예시

아래의  예시는 본 셸과 호환되며  및 에 대해 csh와 유사한 시맨틱을 제공한다. `[ -r filename ] && cmd`는 파일이 존재하고 읽기 가능한지 테스트하여 그렇지 않으면  뒤의 부분을 건너뛰는 단락 평가다.

:
```bash
[ -r ~/.profile ] && ~/.profile             # 환경 설정, 한 번만, 본 셸 구문 전용
if [ -n "$PS1" ]; then                      # 상호작용형인가?
   [ -r ~/.bashrc     ] && ~/.bashrc        # 상호작용형 셸을 위한 tty/프롬프트/함수 설정
   [ -r ~/.bash_login ] && ~/.bash_login    # 로그인 셸 전용 로그인 작업
fi                                          # "if" 블록 끝
```


* 배시 시작 시의 운영체제 문제

일부 유닉스 및 리눅스 버전은 일반적으로  디렉터리 아래에 배시 시스템 시작 스크립트를 포함하고 있다. 배시는 표준 초기화의 일부로 이 파일들을 실행하지만, 다른 시작 파일들은 문서화된 배시 시작 순서와 다른 순서로 이 파일들을 읽을 수도 있다. 루트 사용자의 파일 기본 내용이나 시스템이 설정 시 새 사용자 계정에 제공하는 스켈레톤(skeleton) 파일에도 문제가 있을 수 있다. X 윈도 시스템을 실행하는 시작 스크립트도 창 관리자를 실행하기 전에 사용자 환경 변수를 설정하려는 시도 중에 사용자의 배시 시작 스크립트로 예기치 않은 동작을 할 수 있다. 이러한 문제는 종종  또는  파일을 사용하여 을 읽게 함으로써 해결할 수 있는데, 이는 xterm이나 그놈 단말기 같이 창 관리자에서 생성된 배시 셸 창에 필요한 환경 변수를 제공한다.

### 표준 스트림

표준 스트림 - STDIN, STDOUT, STDERR

## 명령어

### 시스템 명령어

### 별칭

### 키워드와 예약어

* 
** 이 특정 키워드를 포함하는 배시 함수 선언은 본/콘/POSIX 스크립트와 호환되지 않지만, 배시는 본, 콘 및 POSIX 준수 셸에서 사용되는 함수 선언 구문도 수용한다.

### 함수

### 내장 명령어

* 다양한 내장 명령어:
** POSIX 특수 내장 명령어:
*** ,  등.
** 
*** Xtrace: [  |  ]. 셸의 일차적인 디버깅 수단. xtrace와 verbose는 모두  명령어로 동시에 끌 수 있다.
*** Verbose: [  |  ]. 배시가 명령어를 읽을 때 터미널에 출력한다. 배시는 if-fi나 case-esac 블록을 포함하는 복합 명령어 같은 구조를 한꺼번에 읽는다. 복합 명령어 내에 가 포함된 경우, "verbose"는 배시가 다음에 코드를 입력으로 읽을 때, 즉 현재 실행 중인 구조가 끝난 후에 활성화된다.
*** xtrace와 verbose는 모두  명령어로 동시에 끌 수 있다.
** 
*** expand-aliases: 상호작용 셸에서 기본적으로 켜져 있다. 일부 개발자들은 스크립트에서의 사용을 권장하지 않는다.

### PATH와 시스템 명령어

셸이 외부 명령어를 찾을 때, 본 셸 변수 에 의존한다. 는 콜론 으로 구분된 디렉터리 목록을 포함한다. 가장 왼쪽 디렉터리부터 시작하여 왼쪽에서 오른쪽 방향으로 일치하는 항목을 찾을 때까지 각 디렉터리를 검색한다. 리눅스에서 사용자가 추가 명령어를 찾을 수 있도록, 배포판 관리자와 패키지 개발자가  및 기타 위치에 소스 파일을 포함하여 최종 사용자의  값을 변경하는 것이 일반적인 관행이다.

예를 들어  명령어를 찾을 때, 내부 명령어를 고려한 후 아무것도 찾지 못하면 배시는 의 디렉터리들을 검색하여 검색 문자열과 일치하는 베이스 이름을 가진 첫 번째 실행 파일의 절대 경로를 선택한다.

에 나열된 디렉터리에  명령어가 두 개 이상 있는 경우, 명령줄을 파싱하고 실행하는 과정에서 기본적으로 첫 번째로 발견된 명령어만 선택된다.  조회는 느리다. 셸은 해시 테이블에 명령어 위치를 기억함으로써 명령줄 실행 프로세스의 속도를 높인다. 해시 테이블의 간섭 없이 전체  검색을 수행하려면 로 현재 테이블을 제거하고 로 모든 종류의 명령어를 검색한다.

:
```console
$ # 전체 경로 검색 강제
$ PATH=${PATH}:${HOME}
$ printf 'echo script_file: "$@"\n' > ./echo
$ chmod 0700 ./echo
$ hash -r; type -a echo
echo is a shell builtin
echo is /usr/bin/echo
echo is /home/liveuser/echo
$
```


 문자열에서 나중에 발견되는 명령어로 명령줄을 실행하려면 절대 경로를 지정하거나 현재 작업 디렉터리를 기준으로 경로 해결을 고정할 수 있다.

:
```console
$ /home/liveuser/echo foo
script_file: foo
$ ./echo bar
script_file: bar
$
```


보안상의 이유로 PATH의 디렉터리들이 누구나 쓸 수 없거나(world-writeable), 루트 및 신뢰할 수 있는 사용자만 쓸 수 있도록 하는 것이 권장된다.

### 명령어 조회

* 명령어 위치: 확장 후 명령줄 전체 텍스트의 첫 번째 단어.
* 명령어 이름 조회가 다음 순서로 수행된다:
** 셸 내부 명령어:
*** 셸 별칭,
*** 셸 예약어,
*** 셸 함수, 그리고
*** 셸 내장 명령어;
** PATH 셸 변수를 사용한 셸 외부 명령어:
***  또는  같은 별도의 유닉스 스타일 프로그램, 그리고
*** 실행 명령어를 포함하는 파일인 셸 스크립트.
* 결과 문자열이 명령어로 실행된다.

## 제어 구조

### 서브셸

서브셸: ;

### 파이프라인

하지만 파이프라인을 사용함으로써 여러 계산 주기에 동시에 참여할 수 있어 속도를 실질적으로 높일 수 있다. 파이프라인된 제어 장치에서는 서로 다른 명령어들이 동시에 프로세스를 통과하지만 시점은 서로 다르다. 한 명령어가 인출되는 동안 두 번째 명령어는 해독되는 식이다. 유닉스 스타일 파이프라인: `|`.

### 논리 연산자

* AND ()
* OR ()
* NOT ()

배시는 이전 명령어가 설정한 종료 상태에 따라 명령어 실행을 결정하는 "조건부 실행" 명령어 구분자를 제공한다. 예를 들어:


```console
$ cd "$SOMEWHERE" && ./do_something || echo "An error occurred" >&2
```


여기서 은 (디렉터리 변경) 명령어가 "성공"(종료 상태 0 반환)한 경우에만 실행되고,  명령어는  또는  명령어가 "오류"(0이 아닌 종료 상태 반환)를 반환한 경우에만 실행된다.

### 반복

* , ,  루프 복합 명령어;
* 산술 C-스타일 및 목록 열거형  루프 복합 명령어; 그리고
* , , ,  흐름 제어 명령어.

### 복합 명령어

배시는 또한  및  형태의 조건부 명령어 평가를 지원한다.

### 테스트

파일 속성 테스트, 문자열 및 정수 값 비교 등을 위한 내장 명령어:
* 전통적인  명령어,
* 전통적인 단일 대괄호 테스트: ,
* 현대적인 이중 대괄호 테스트: ..., 다음 고급 기능을 포함:
** 확장 정규 표현식 및 extglob 매칭
**  및 를 사용한 사전식 비교;
*  수치 평가 및 테스트; 산술 및 수치 비교를 위한 거의 모든 "C" 언어 연산자를 포함함;

모든 명령어에 대해 종료 상태는 특수 변수 에 저장된다.

### 정규 표현식

배시 3.0은 펄을 연상시키는 구문을 사용하여 프로세스 내 정규 표현식 매칭을 지원한다. 정규식 매칭은  확장 테스트 구문 내의 =~ 연산자 오른쪽에 있는 문자열로 제한된다.


```bash
[[ $line =~ [[:space:]]*(a)?b ]]
```
는 line의 값이 'aab', ' aaaaaab', 'xaby', ' ab'인 경우 모두 일치하며, 값의 어디든 'b'를 포함하는 줄과도 일치함을 의미한다.

### 코프로세스

## 데이터 조작

### 단어 분할

단어로 분리 (즉, 단어 분할)

### 인용

배시는 특정 인용 규칙을 갖는다:
* 단일 인용부호 
* 이중 인용부호 
* 백슬래시 
* ANSI-C 인용 

, 도 참조하라.

백틱 : 도 참조하라.

### 유니코드

 및 ANSI-C 인용에서의 유니코드 지원.

### 중괄호 확장

:
```console
$ echo kernel{,-headers}
kernel kernel-headers
```


교체라고도 불리는 중괄호 확장은 C 셸에서 복제된 기능이다. 이는 대안적인 조합 세트를 생성한다. 생성된 결과가 파일로 존재할 필요는 없다. 각 확장된 문자열의 결과는 정렬되지 않으며 왼쪽에서 오른쪽 순서가 유지된다:

:
```console
$ echo a{p,c,d,b}e
ape ace ade abe
$ echo {a,b,c}{d,e,f}
ad ae af bd be bf cd ce cf
```


본 셸은 동일한 출력을 생성하지 않으므로 사용자는 이식 가능한 셸 스크립트에서 중괄호 확장을 사용해서는 안 된다.

:
```console
$ # 배시 셸
$/bin/bash -c 'echo a{p,c,d,b}e'
ape ace ade abe
$ # 전통적인 셸은 동일한 출력을 생성하지 않음
$ /bin/sh -c 'echo a{p,c,d,b}e'
a{p,c,d,b}e
```


중괄호 확장이 와일드카드와 결합되면 중괄호가 먼저 확장된 다음 결과 와일드카드가 정상적으로 대체된다. 따라서 현재 디렉터리의 JPEG 및 PNG 이미지 목록은 다음을 사용하여 얻을 수 있다:

:
```bash
ls *.{jpg,jpeg,png}    # *.jpg *.jpeg *.png로 확장된 후,
                       # 와일드카드가 처리됨
echo *.{png,jp{e,}g}   # echo는 확장 결과만 보여줌 –
                       # 중괄호 안의 중괄호도 가능함.
```


교체 외에도 중괄호 확장은 마침표 두 개로 구분된 두 정수 또는 문자 사이의 순차적 범위에 사용할 수 있다. 최신 버전의 배시에서는 증분 값을 지정하기 위해 세 번째 정수를 허용한다.

:
```console
$ echo {1..10}
1 2 3 4 5 6 7 8 9 10
$ echo {01..10}
01 02 03 04 05 06 07 08 09 10
$ echo file{1..4}.txt
file1.txt file2.txt file3.txt file4.txt
$ echo {a..e}
a b c d e
$ echo {1..10..3}
1 4 7 10
$ echo {a..j..3}
a d g j
```


중괄호 확장이 변수 확장(일명 매개변수 확장 및 매개변수 치환)과 결합될 때, 변수 확장은 중괄호 확장 이후에 수행되며, 이는 경우에 따라  내장 명령어의 사용을 필요로 할 수 있다:

:
```console
$ start=1; end=10
$ echo {$start..$end} # 평가 순서 때문에 확장에 실패함
{1..10}
$ eval echo {$start..$end} # 변수 확장이 발생한 후 결과 문자열이 평가됨
1 2 3 4 5 6 7 8 9 10
```


### 틸드 확장

### 매개변수 및 변수 확장

* 유형
* 셸 매개변수
* 환경 변수
* 사용자 변수
* 스코프
* 배열
** 인덱스 배열: 크기 제한 없음.
** 연관 배열: 를 통해.
* 매개변수 확장
*:외부 유틸리티보다 특정 작업을 더 빠르게 수행할 수 있는 확장 구문들(일부 예시):
** 패턴 치환
***  (`sed ''` 대용),
** 일치하는 접두사 또는 접미사 패턴 제거
***  ( 대용),
** 배열 키 열거
*** , 그리고
** Null이거나 설정되지 않은 경우 오류 표시
*** ,

### 경로명 확장

경로명 확장, 즉 , , 를 사용한 셸 스타일 글로브 및 패턴 매칭.

### 로캘

 인용 구문을 통한 로캘별 번역.

## 프로세스 리다이렉션 및 파싱

### 명령어 치환

명령어 치환: ,

### 프로세스 치환

프로세스 치환,  또는  (시스템이 지원하는 경우):

배시는  및  구문을 사용한 프로세스 치환을 지원하며, 이는 일반적으로 파일 이름이 사용되는 위치에 명령어의 출력(또는 입력)을 대체한다. (이는 지원하는 시스템에서 /proc/fd/ 무명 파이프를 통해, 또는 필요한 경우 임시 명명된 파이프를 통해 구현된다.)

### 산술 확장

산술 확장,  또는 , 다음을 포함:
* 2에서 64까지의 임의의 밑을 가진 정수 산술, 다만
* 부동소수점 산술은 셸 자체 내에서는 사용할 수 없다(이 기능에 대해서는 최신 버전의  및  등을 참조).

배시는 외부 프로세스를 생성하지 않고도 정수 계산("산술 평가")을 수행할 수 있다. 이를 위해  명령어와  변수 구문을 사용한다.

### 리다이렉션

표준 입력, 표준 출력 및 표준 오류 데이터 스트림의 리다이렉션이 수행된다. 다음을 포함:
* 파일 쓰기, , 및 추가, ,
* 히어 도큐먼트, ,
* 매개변수를 입력으로 사용할 수 있게 하는 히어 스트링, , 그리고
* 셸의  설정이 활성화되어 있을 때 파일 덮어쓰기를 강제할 수 있는 리다이렉션 연산자 .

배시의 구문은 입출력 리다이렉션을 단순화한다. 예를 들어,  연산자를 사용하여 표준 출력과 표준 오류를 동시에 재지정할 수 있다. 이는 본 셸의 상응하는 방식인 ''보다 입력하기 쉽다. 배시는 히어 도큐먼트를 지원한다. 버전 2.05b부터 배시는  연산자를 사용하여 "히어 스트링"으로부터 표준 입력을 재지정할 수 있다.

### 명령어 파싱

*(A) 인용되지 않은 (해시)부터 같은 줄 끝까지의 주석은 무시된다;

*(B) 명령어는 한 번에 한 줄씩 파싱된다:
** 제어 구조가 존중된다.
** 줄 끝에서의 백슬래시  이스케이프도 존중된다.
*(C) 인용 규칙에 따라 단어로 분리된다(즉, 단어 분할).
** ANSI-C 인용 을 포함한다.
*(D) 결과 문자열에 대해 다음 순서로 일곱 가지 유형의 확장이 수행된다:
*# (유형 1) 중괄호 확장 `kernel{-headers}`,
*# (유형 2) 틸드 확장 ,
*# 왼쪽에서 오른쪽 방향으로:
*#* (유형 3) 매개변수 및 변수 확장  또는 , 다음을 포함:
*#* (유형 4) 명령어 치환: ,
*#* (유형 5) 프로세스 치환,  또는  (시스템 지원 시):
*#* (유형 6) 산술 확장,  또는 , 다음을 포함:
*#** 2에서 64까지의 임의의 밑을 가진 정수 산술, 다만
*#** 부동소수점 산술은 셸 자체 내에서는 사용할 수 없다.
*# 다시 단어 분할이 수행된다.
*# (유형 7) 경로명 확장, 즉 , , 를 사용한 셸 스타일 글로브 및 패턴 매칭.
*# 인용부호 제거.
*(E) 표준 입력, 표준 출력 및 표준 오류 데이터 스트림의 리다이렉션이 수행된다. 다음을 포함:
** 파일 쓰기, , 및 추가, ,
** 히어 도큐먼트, ,
** 히어 스트링, , 그리고
** 리다이렉션 연산자 .
*(F) 명령어 이름 조회가 다음 순서로 수행된다:
*# 셸 내부 명령어:
*#* 셸 별칭,
*#* 셸 예약어,
*#* 셸 함수, 그리고
*#* 셸 내장 명령어;
*# 셸 외부 명령어:
*#*  또는  같은 별도의 유닉스 스타일 프로그램, 그리고
*#* 셸 스크립트.
*(G) 결과 문자열이 명령어로 실행된다.

## 상호작용 전용 기능

### 명령어 기록

무제한 크기의 명령어 기록. 이 기능은 상호작용 모드에서만 사용할 수 있다.

### 디렉터리 스택

디렉터리 스택(및 내장 명령어) 기능은 상호작용 모드에서만 사용할 수 있다.

### 프로그래밍 가능한 완성

"탭 완성" 또는 "명령줄 자동 완성"이라고도 알려진 이 기능은 사용자가 상호작용형 명령 셸 내에서 을 누를 때, 배시가 사용 가능한 완성 스크립트를 자동으로 사용하여 부분적으로 입력된 프로그램 이름, 파일 이름 및 변수 이름을 제안하는 기능이다. 배시의 명령줄 완성 시스템은 매우 유연하고 사용자 정의가 가능하며, 종종 특정 프로그램 및 작업을 위한 인자와 파일 이름을 완성하는 함수와 함께 패키징된다.

배시는 내장된 , ,  명령어를 통해 프로그래밍 가능한 완성을 지원한다. 이 기능은 2000년에 출시된 2.04 베타 버전부터 제공되었다. 이러한 명령어들은 명령어(즉, 설치된 프로그램), 함수, 변수 및 파일 이름에 대해 복잡하고 지능적인 완성 사양을 가능하게 한다.

와  두 명령어는 readline 입력에서 사용 가능한 일부 명령어 또는 옵션의 인자가 어떻게 나열될지 지정한다. 버전 5.1 기준으로 명령어 또는 옵션의 완성은 대개 이름을 입력한 후  키를 눌러 활성화된다. 이 기능은 상호작용 모드에서만 사용할 수 있다.

### 프롬프트

구성 가능한 프롬프트. 이 기능은 상호작용 모드에서만 사용할 수 있다.

## 문서화

### 사용자 매뉴얼

배시를 위한 사용자 매뉴얼은 GNU 프로젝트에서 제공한다. 이는 때때로 man page보다 더 사용자 친화적인 문서로 간주된다. "시스템의 ,  또는 이와 유사한 디렉터리를 찾아봄으로써 배시에 관한 정보를 찾을 수도 있다." GNU/리눅스 시스템에서  프로그램을 사용할 수 있는 경우, 설치된 버전에 맞는 GNU 매뉴얼을 에서 볼 수 있다.

### Man page

최신 기술 매뉴얼 또는 'man page'는 배시가 작동하는 방식을 이해하기 위한 권위 있는 설명 기술 문서로 의도되었다. GNU/리눅스 시스템에서 설치된 버전에 맞는 문서는 대개  프로그램을 통해 에서 확인할 수 있다.

### help 내장 명령어

최신 버전의 배시에서는 터미널 프롬프트에서 ,  또는 를 실행하여 셸 내장 명령어에 대한 정보를 찾을 수 있다.

 명령어는 를 통해 호출함으로써 셸의 검색 경로를 통해 발견된 프로그램을 실행하고 셸 별칭이나 내장 함수가 실행되지 않도록 보장할 수 있다: .

### POSIX 사양

서로 다른 운영체제에서 실행되는 서로 다른 셸 프로그램 간의 상호 운용성을 위해 POSIX 사양은 현대의 유닉스 계열 셸이 작성되는 방식에 영향을 미친다. 배시는 "IEEE POSIX 사양(IEEE Standard 1003.1)의 IEEE POSIX '셸 및 유틸리티' 부분을 준수하는 구현으로 의도되었다." 이 표준의 최신 간행물(2024년)은 온라인에서 확인할 수 있다.

배시의 기반이 되는 표준인 POSIX 표준, 또는 IEEE Std 1003.1 등은 특히 많은 정보를 담고 있다.

### 추가 자료

"프로젝트 유지 관리자는 자주 묻는 질문(FAQ)을 포함하는 배시 페이지를 운영하고 있다." 이 FAQ는 배시 버전 5.1 기준이며 더 이상 업데이트되지 않는다.

비공식적인 지원 채널은 libera.chat의 IRC #bash 채널에서 이용 가능하며, 메일링 리스트는 Bash - GNU 프로젝트 - 자유 소프트웨어 재단에서 확인할 수 있다.

## 보안 및 취약점

### 루트 스크립트

루트 사용자로 셸 스크립트를 실행하는 것은 수년 동안 나쁜 보안 관행으로 널리 비판받아 왔다. 흔히 언급되는 한 가지 이유는 스크립트가 루트로 실행될 때 스크립트 내의 버그로 인한 부정적인 영향이 루트의 승격된 권한에 의해 확대되기 때문이다.

흔한 예시로, 스크립트에  명령어가 포함되어 있지만  변수가 정의되지 않은 경우가 있다. 리눅스에서 이 스크립트가 일반 사용자에 의해 실행되었다면 셸은  명령어를 일반 사용자로 실행하려고 시도할 것이고 명령어는 실패할 것이다. 그러나 스크립트가 루트 사용자에 의해 실행되었다면 명령어는 성공하여 파일 시스템이 삭제될 가능성이 높다.

대신 명령어 단위로 를 사용하는 것이 권장된다.

### CGI 스크립트

CGI 스크립트는 중대한 취약점의 원천이다.

### 내장 명령어

"eval 명령어는 매우 강력하며 남용하기 매우 쉽다."

### 입력 유효성 검사

"입력 유효성 검사는 데이터가 데이터 클렌징을 거쳐 정확하고 유용한 데이터 품질을 갖추었음을 보장하는 프로세스다."

### 셸쇼크

2014년 9월, 프로그램에서 보안 버그가 발견되었다. 이는 "셸쇼크"라고 명명되었다. 공개적 노출은 곧바로 인터넷 전반에 걸친 다양한 공격으로 이어졌다.

취약점 악용을 통해 특정 버전의 배시에서 실행 가능한 CGI 스크립트 내에서 임의 코드 실행이 가능해질 수 있었다. 이 버그는 배시가 환경 변수를 통해 서브셸에 함수 정의를 전달하는 방식과 관련이 있었다. 이 버그는 1989년 8월(버전 1.03)부터 소스 코드에 존재해 왔으며, 2014년 9월(버전 4.3)에 패치되었다.

버그가 확인된 직후 버그를 수정하기 위한 패치가 제공되었다. 최신 버전으로 업그레이드하는 것이 강력히 권장된다.

이 버그에는 다른 것들 중에서도 CVE 식별자  등이 할당되었다. CVSS Metrics 2.x 및 3.x에서 이 버그는 각각 "높음" 및 "심각"으로 간주된다.

## 지원 중단된 구문

* 백틱 스타일 명령어 치환: 는 다음으로 인해 지원 중단되었다:
** ;
* //`[[` 명령어에서의  또는  사용,
** 예를 들어 는 다음으로 인해 지원 중단되었다:
*** ;
* 산술 구문 의 사용은 다음으로 인해 지원 중단되었다:
**  또는
** 상황에 따라 ;
* 파이프라인으로서의  사용은 |를 위해 지원 중단되었다;
*  또는 의 모든 사용.

## 디버깅

### 기능 일람표

* POSIX에 의해 규정된 셸 기능:
** 매개변수 확장:
** 특수 매개변수:
** 특수 내장 유틸리티 :
** 특수 내장 유틸리티 :
*** POSIX는  내장 명령어의 특정 사용법을 규정한다.
** 유틸리티 : 변수 내용을 신뢰할 수 있게 출력하는 수단.
* POSIX에 의해 규정되지 않은 배시 기능:
** 배시 변수:
** 셸 내장 명령어 :
** 셸 내장 명령어 :
** 셸 내장 명령어 :
*** POSIX가  내장 명령어의 특정 사용법을 규정하지만, 다음 신호 지정은 배시 확장 기능이다: ...
* 제3자 디버깅 유틸리티:
** ShellCheck: 셸 스크립트 분석 도구;
** devscripts-checkbashisms: /bin/sh 스크립트에 배시 전용 구문이 포함되어 있는지 확인;
** kcov: 특별한 컴파일 옵션 없이 사용하는 코드 커버리지 도구;
** Bashdb: 배시 기호 디버거.

#### 예시

 매개변수 확장을 사용하면 설정되지 않았거나 null인 변수가 스크립트를 중단시킬 수 있다.

:
```console
$ cat ex.sh
#!/bin/bash
bar="foo is not defined"
echo "${foo:?$bar}"
echo this message doesn't print

$ ./ex.sh
./ex.sh: line 3: foo: foo is not defined
$
```


공백과 개행 문자를 포함하는 배열의 내용을 먼저 이식 가능한 구문으로 출력한 후, 배시에서 동일하게 수행하는 방법. POSIX에는 명명된 배열이 없으며 오직  내장 명령어로 재설정할 수 있는 인자 목록 만 있음에 유의하라.

:
```console
$ # POSIX 셸에서:
$ set -- "a" " b" "
>  c "
$ printf ',%s,\n' "$@"
,a,
, b,
,
 c,
```


배시에서는 개행 문자 전의 공백 수가 명확해진다는 점에 유의하라.

:
```console
$ # 배시에서:
$ array=( "a" " b" "
>  c " )
$ declare -p array
declare -a array=([0]="a" [1]=" b" [2]=$' \n c ')
```


문제가 발생했을 때 오류 메시지를 출력하는 방법.

:
```console
$ cat error.sh
#!/bin/env bash
if ! lsblk | grep sdb
then
  echo Error, line "${LINENO}"
fi
$ ./error.sh
Error, line 130
```


xtrace 사용 예시. 만약 errexit가 활성화되어 있었다면 는 실행되지 않았을 것이다.

:
```console
$ cat test.sh
#!/bin/env bash
set -x
foo=bar; echo "${foo}"
false
echo quux
$ ./test.sh
+ foo=bar
+ echo bar
bar
+ false
+ echo quux
quux
```


참고: 는 재초기화가 필요 없는 서브셸과 같은 특정 상황에서 와 다르다.

:
```console
$ echo $(echo $BASHPID $$)   $$    $BASHPID
              25680    16920 16920 16920
#             |        |     |     |
#             |        |     |     \-- 서브셸 외부의 $BASHPID
#             |        |     \-- 서브셸 외부의 $$
#             |        \-- 서브셸 내부의 $$
#             \-- 서브셸 내부의 $BASHPID
```


### 버그 보고

bashbug라는 외부 명령어는 배시 셸 버그를 보고한다. 명령어가 호출되면 사용자의 기본 편집기가 양식과 함께 나타난다. 양식을 작성하여 배시 유지 관리자(또는 선택적으로 다른 이메일 주소)에게 메일로 보낸다.

## 역사

셸 스크립트 기능은 같은 이름의 1963년 매크로 프로세서를 참조한 "RUNCOM"이라는 파일에서 유래했다. 접미사 "rc"는 "runcom"의 약자다. "셸"이라는 용어는 1964년 또는 1965년에 Louis Pouzin에 의해 만들어졌으며, 그의 1965년 논문 "The SHELL, A Global Tool for Calling and Chaining Procedures in the System"에 등장했다. 이 논문은 나중에 많은 유닉스 셸에서 발견되는 많은 기능을 설명하고 있다. 문자 인코딩을 위한 ASCII 표준은 1969년 RFC 20이라는 문서에서 정의되었다.

### 타임라인

배시 역사상의 중요한 사건들은 다음과 같다:

## 같이 보기
* GNU readline

## 각주

; 내용주


## 외부 링크
* 
* 

분류:유닉스 셸
분류:스크립트 언어
분류:GNU 프로젝트 소프트웨어
분류:크로스 플랫폼 자유 소프트웨어
분류:1989년 소프트웨어
분류:C로 작성된 자유 소프트웨어
분류:텍스트 지향 프로그래밍 언어