Linux / 리눅스 Bash 명령어 연결 연산자: ;, &&, ||, &, | 사용법
리눅스 Bash에서 ;는 앞 명령의 성공 여부와 관계없이 다음 명령을 실행하고, &&는 앞 명령이 성공했을 때만, ||는 앞 명령이 실패했을 때만 다음 명령을 실행합니다. 세 기호의 차이는 명령이 돌려주는 종료 상태(exit status)를 기준으로 이해하면 간단합니다.
짧은 명령을 한 줄에 연결할 때는 편리하지만, 실행 조건을 잘못 이해하면 배포·삭제·백업 같은 작업에서 의도하지 않은 명령이 실행될 수 있습니다. 이 글에서는 세 연산자의 기본 문법과 평가 순서뿐 아니라, 함께 알아둘 백그라운드 실행 &, 파이프 |·|&, 종료 상태 반전 !까지 설명합니다.
Bash 명령 실행 기호 한눈에 보기
| 연산자 | 다음 명령의 실행 조건 | 주요 용도 |
|---|---|---|
; |
앞 명령의 성공·실패와 무관하게 실행 | 서로 독립적인 명령을 순서대로 실행할 때 사용합니다. |
&& |
앞 명령이 성공했을 때만 실행 | 설치, 빌드, 배포처럼 앞 단계가 성공해야 다음 단계가 의미 있을 때 사용합니다. |
|| |
앞 명령이 실패했을 때만 실행 | 오류 메시지 출력, 대체 명령 실행과 간단한 복구에 사용합니다. |
& |
완료를 기다리지 않고 백그라운드에서 실행 | 오래 걸리는 작업을 비동기적으로 실행하고 터미널을 계속 사용할 때 활용합니다. |
| |
앞 명령의 표준 출력을 뒤 명령의 입력으로 연결 | 출력 필터링, 검색, 정렬처럼 여러 명령이 데이터를 이어서 처리하게 합니다. |
|& |
표준 출력과 표준 오류를 함께 뒤 명령으로 전달 | 정상 출력과 오류를 한꺼번에 기록하거나 필터링할 때 사용합니다. |
! |
명령 또는 파이프라인의 종료 상태를 반전 | 실패한 경우를 성공 조건으로 검사해야 할 때 사용합니다. |
GNU Bash 매뉴얼은 ;, &, &&, ||를 명령 목록(list)을 구성하는 연산자로 설명합니다. |와 |&는 명령의 입출력을 잇는 파이프라인 연산자이며, !는 파이프라인의 종료 상태를 반전하는 예약어입니다.
실행 조건을 결정하는 종료 상태란?
Bash에서 명령은 실행이 끝날 때 0부터 255 사이의 종료 상태를 반환합니다. 일반적으로 0은 성공, 0이 아닌 값은 실패를 의미합니다. 마지막으로 실행한 명령의 종료 상태는 특수 매개변수 $?로 확인할 수 있습니다.
true echo $? false echo $?
true는 성공을 의미하는 0을 반환하고, false는 실패를 의미하는 0이 아닌 값을 반환합니다. &&와 ||는 화면에 출력된 문구가 아니라 바로 이 종료 상태를 확인합니다.
명령을 찾지 못했을 때 Bash는 일반적으로 127을, 명령은 찾았지만 실행할 수 없을 때는 126을 반환합니다. 신호로 종료된 명령에는 다른 규칙이 적용될 수 있으므로 모든 실패가 1을 반환한다고 가정하면 안 됩니다. 중요한 기준은 구체적인 숫자보다 0인지 아닌지입니다.
세미콜론 ; 사용법: 결과와 무관하게 계속 실행
세미콜론은 여러 명령을 한 줄에서 순서대로 구분합니다. Bash는 앞 명령이 끝나기를 기다린 다음 성공 여부와 관계없이 뒤 명령을 실행합니다. 줄바꿈도 대부분의 명령 목록에서 세미콜론과 같은 구분 역할을 합니다.
command1 ; command2
다음 예제에서는 파일 복사에 실패하더라도 마지막 ls가 실행됩니다.
mkdir -p backup ; cp report.txt backup/ ; ls -l backup/
세 명령이 서로 독립적이라면 간결한 표현입니다. 하지만 report.txt 복사가 성공한 경우에만 목록을 확인하거나 후속 작업을 해야 한다면 세미콜론보다 &&가 적합합니다.
&&와 || 사용법: 성공과 실패에 따라 실행
&&는 앞 명령이 성공해야 다음 명령을 실행합니다
&&로 연결된 명령은 앞 명령의 종료 상태가 0일 때만 다음 명령으로 진행합니다. 이를 단락 평가(short-circuit evaluation)라고 합니다. 앞 단계가 실패하면 뒤 명령은 평가할 필요가 없으므로 실행하지 않습니다.
command1 && command2
패키지 목록을 정상적으로 갱신한 경우에만 업그레이드를 실행하려면 다음과 같이 작성할 수 있습니다.
sudo apt update && sudo apt upgrade
소스 디렉토리로 이동한 뒤 빌드하는 경우에도 유용합니다. cd가 실패했는데 현재 디렉토리에서 실수로 빌드하는 상황을 막을 수 있습니다.
cd /srv/myapp && make
||는 앞 명령이 실패해야 다음 명령을 실행합니다
||로 연결된 뒤 명령은 앞 명령의 종료 상태가 0이 아닐 때만 실행됩니다. 실패를 알리거나 대체 동작을 시도할 때 적합합니다.
command1 || command2
설정 파일이 있는지 검사하고, 없으면 안내 메시지를 출력하는 예제입니다.
test -f /etc/myapp.conf || echo "설정 파일이 없습니다."
디렉토리가 없을 때만 생성하려면 다음처럼 사용할 수 있습니다. 다만 실제 작업에서는 mkdir -p 자체가 이미 존재하는 디렉토리를 허용하므로 더 간단한 방법이 될 수 있습니다.
test -d backup || mkdir backup
백그라운드 실행, 파이프라인과 상태 반전
&는 명령을 기다리지 않고 백그라운드에서 실행합니다
명령 끝에 &를 붙이면 Bash는 해당 명령을 비동기적으로 실행하고 완료를 기다리지 않은 채 다음 입력을 받을 수 있습니다. 장시간 실행되는 작업을 시작한 뒤 같은 터미널에서 다른 명령을 실행할 때 유용합니다.
./long-job.sh > job.log 2>&1 &
마지막 &는 백그라운드 실행을 의미하고, 앞의 >와 2>&1은 출력을 파일로 보내는 리디렉션입니다. 백그라운드 작업은 jobs로 확인하고 fg 또는 bg로 제어할 수 있습니다. 터미널을 닫은 뒤에도 실행을 유지해야 한다면 서비스 관리자나 별도의 세션 관리 도구를 사용하는 편이 안전합니다.
|는 앞 명령의 출력을 뒤 명령의 입력으로 전달합니다
파이프 |는 앞 명령의 표준 출력(stdout)을 뒤 명령의 표준 입력(stdin)으로 연결합니다. 앞 명령의 성공 여부에 따라 실행을 선택하는 ||와 달리, 파이프는 명령 사이에 데이터를 전달합니다.
ps aux | grep nginx | sort
이 예제에서는 프로세스 목록을 grep이 받아 nginx가 포함된 줄을 찾고, 그 결과를 sort가 정렬합니다. 각 명령의 출력 전체를 임시 파일에 저장하지 않고 연속적으로 처리할 수 있습니다.
|&는 표준 오류까지 함께 전달합니다
|&는 앞 명령의 표준 출력과 표준 오류(stderr)를 모두 뒤 명령의 입력으로 보냅니다. Bash에서는 2>&1 |를 간단히 쓴 형태입니다.
./build.sh |& tee build.log
빌드의 정상 메시지와 오류 메시지를 화면에 표시하면서 같은 내용을 로그 파일에 저장할 수 있습니다. 표준 오류를 별도로 처리해야 한다면 |& 대신 명시적인 리디렉션을 사용하는 것이 좋습니다.
!는 명령이나 파이프라인의 성공과 실패를 뒤집습니다
명령이나 파이프라인 앞에 !를 두면 종료 상태가 논리적으로 반전됩니다. 원래 종료 상태가 0이면 실패로, 0이 아니면 성공으로 평가합니다.
if ! grep -q "enabled" app.conf; then echo "설정이 활성화되어 있지 않습니다." fi
이 패턴은 특정 문자열을 찾지 못했을 때처럼 실패 조건을 명확하게 처리하는 데 유용합니다. 명령의 출력 자체를 반전하는 것이 아니라 종료 상태만 반전한다는 점에 주의해야 합니다.
파이프라인 오류는 pipefail 설정에 따라 달라집니다
기본적으로 파이프라인의 종료 상태는 마지막 명령의 종료 상태입니다. 앞쪽 명령이 실패해도 마지막 명령이 성공하면 파이프라인 전체가 성공으로 보일 수 있습니다. 파이프라인 안의 실패를 감지해야 하는 스크립트에서는 pipefail 옵션을 검토합니다.
set -o pipefail command1 | command2 | command3
pipefail이 활성화되면 모든 명령이 성공한 경우에만 파이프라인이 0을 반환합니다. 하나 이상 실패하면 가장 오른쪽에서 실패한 명령의 0이 아닌 종료 상태를 반환합니다.
여러 연산자를 섞을 때 평가 순서
&&와 ||는 우선순위가 같고 왼쪽부터 평가됩니다
Bash의 명령 목록에서 &&와 ||는 같은 우선순위를 가지며 왼쪽 결합 방식으로 평가됩니다. 따라서 다음 명령은 단순히 “첫 명령이 성공하면 두 번째, 실패하면 세 번째”라고만 해석해서는 안 됩니다.
command1 && command2 || command3
command1이 성공하면 command2가 실행됩니다. 그런데 command2가 실패하면 전체 왼쪽 표현의 결과가 실패가 되므로 command3도 실행됩니다. 즉, 두 번째 명령의 실패까지 세 번째 명령의 실행 조건에 영향을 줍니다.
true && false || echo "이 문장은 실행됩니다."
if-else가 필요하면 조건문을 명확하게 작성합니다
두 번째 명령의 성공 여부와 관계없이 첫 번째 명령만 기준으로 두 갈래를 나눠야 한다면 && ... || ...를 if-else의 축약형처럼 쓰지 않는 것이 안전합니다. 의도를 명확하게 드러내는 if 문을 사용합니다.
if command1; then command2 else command3 fi
여러 명령을 하나의 성공 또는 실패 단위로 묶어야 할 때는 중괄호나 괄호를 사용할 수 있습니다. 중괄호 그룹은 현재 셸에서 실행되며 닫는 중괄호 앞에 세미콜론이나 줄바꿈이 필요합니다.
command1 && {
command2
command3
}
괄호 그룹은 서브셸에서 실행되므로 그룹 안에서 변경한 현재 디렉토리나 일반 셸 변수는 그룹 밖에 그대로 남지 않습니다.
( cd /srv/myapp && make ) || echo "빌드에 실패했습니다."
실무에서 자주 쓰는 명령 연결 패턴
필수 단계가 모두 성공해야 배포하기
빌드와 테스트가 모두 성공한 경우에만 배포 명령을 실행하도록 연결할 수 있습니다. 중간 단계가 하나라도 실패하면 이후 단계는 실행되지 않습니다.
make && make test && ./deploy.sh
실패 메시지를 남기고 종료하기
필수 파일이 없을 때 메시지를 표준 오류로 보내고 명시적인 실패 상태로 종료하는 패턴입니다.
test -f app.conf || {
echo "app.conf 파일이 필요합니다." >&2
exit 1
}
주 작업 뒤에 정리 명령을 항상 실행하기
작업의 성공 여부와 관계없이 임시 파일을 지우려면 세미콜론을 사용할 수 있습니다.
./process-data.sh ; rm -f /tmp/myapp.lock
다만 스크립트가 중간에 종료되거나 신호를 받는 경우까지 확실히 정리해야 한다면 세미콜론만으로는 부족합니다. 이런 경우에는 Bash의 trap을 사용해 종료 시 정리 작업을 등록하는 편이 안전합니다.
대화형 명령과 셸 스크립트에서의 선택 기준
터미널에서 짧게 실행할 때는 &&와 ||가 빠르고 읽기 쉽습니다. 예를 들어 디렉토리 이동 후 파일을 확인하거나, 명령 실패 시 메시지를 출력하는 정도는 한 줄로 충분합니다.
반면 운영 스크립트에서 분기마다 여러 명령을 실행하거나 로그·재시도·복구가 필요하다면 if, 함수와 명시적인 exit를 사용하는 편이 좋습니다. 짧게 쓰는 것보다 실패 지점과 후속 동작을 분명히 표현하는 것이 유지보수에 유리합니다.
set -e를 켜면 오류 처리가 자동으로 해결된다고 생각하기 쉽지만, 조건식과 &&·|| 목록 안에서는 동작을 주의해야 합니다. 중요한 스크립트라면 각 명령의 실패를 명시적으로 검사하고 필요한 메시지와 종료 상태를 직접 정하는 것이 안전합니다.
자주 하는 실수
;뒤 명령이 앞 명령의 성공을 보장한다고 생각하는 경우: 세미콜론은 성공 여부를 검사하지 않습니다.- 화면 출력으로 성공을 판단하는 경우:
&&와||는 출력 내용이 아니라 종료 상태를 사용합니다. A && B || C를 완전한 if-else로 사용하는 경우: B가 실패해도 C가 실행됩니다.- 긴 배포 절차를 한 줄로 연결하는 경우: 어느 단계에서 실패했는지 파악하기 어려우므로 스크립트와 명시적인 오류 처리가 낫습니다.
- 명령 자체의 종료 상태를 확인하지 않는 경우: 일부 명령은 경고를 출력해도 0을 반환하거나 기대와 다른 조건에서 실패 상태를 반환할 수 있습니다.
자주 묻는 질문
세미콜론과 줄바꿈은 같은가요?
일반적인 명령 목록에서는 하나 이상의 줄바꿈이 세미콜론과 같은 명령 구분 역할을 합니다. 다만 따옴표, 역슬래시, 파이프와 복합 명령처럼 셸이 입력이 끝나지 않았다고 판단하는 문맥에서는 줄바꿈 처리가 달라질 수 있습니다.
&& 뒤 명령이 실행되지 않으면 무엇을 확인해야 하나요?
앞 명령을 단독으로 실행한 뒤 echo $?로 종료 상태를 확인합니다. 0이 아닌 값이라면 && 뒤 명령이 실행되지 않는 것이 정상입니다. 권한, 파일 경로, 옵션과 입력값도 함께 점검해야 합니다.
||는 오류를 무시하는 연산자인가요?
아닙니다. ||는 앞 명령이 실패했을 때 뒤 명령을 실행할 뿐입니다. 최종 명령이 성공하면 전체 목록의 종료 상태가 0이 될 수 있으므로, 원래 오류를 로그로 남기거나 다시 실패 상태로 종료해야 하는지 의도적으로 결정해야 합니다.
&와 &&는 어떻게 다른가요?
&는 명령을 비동기적으로 백그라운드에서 실행하고 셸이 완료를 기다리지 않게 합니다. &&는 앞 명령이 끝나고 성공한 경우에만 다음 명령을 실행하는 조건부 연결 연산자입니다.
파이프 |와 ||는 어떻게 다른가요?
|는 앞 명령의 표준 출력을 뒤 명령의 표준 입력으로 연결합니다. ||는 데이터를 전달하지 않고 앞 명령의 실패 여부에 따라 뒤 명령을 실행합니다.
정리
서로 독립적인 명령을 차례로 실행하려면 ;, 앞 단계가 성공한 경우에만 계속하려면 &&, 실패했을 때 대체 동작을 실행하려면 ||를 사용합니다. 완료를 기다리지 않으려면 &, 명령 사이에 데이터를 전달하려면 | 또는 |&, 성공과 실패를 반대로 평가하려면 !를 사용합니다.
짧은 터미널 작업에는 명령 연결 연산자가 효율적이지만, 여러 단계와 복구 로직이 포함된 작업은 조건문과 함수로 풀어 쓰는 편이 안전합니다. 특히 A && B || C는 B의 실패에도 C가 실행된다는 점을 기억해야 합니다.









