Profile picture

[Linux] xargs 명령어 가이드

JaehyoJJAng2023년 03월 15일

xargs란?

xargs표준 입력(stdin) 으로부터 값을 받아서, 명령어의 인자(argument) 로 넘겨주는 역할을 합니다.

즉, 어떤 명령어가 출력한 리스트를 받아서, 이를 또 다른 명령어에 넘겨주는 중간 역할을 합니다.


기본 구조

command1 | xargs command2
  • command1의 출력 결과를
  • xargs가 받아서
  • command2에 인자로 넘겨 실행

xargs를 쓰는 이유?

xargs는 파이프(|)로 전달받은 표준 입력(stdin)을 커맨드 라인 인자(argument)로 변환해 주는 역할을 합니다.

예를 들어, find로 찾은 파일 목록을 rm으로 삭제하는 것처럼요.

# 현재 디렉터리의 모든 .log 파일을 찾아 삭제한다
find . -name "*.log" | xargs rm

xargs의 두 가지 모드

xargs에는 두 가지 모드가 존재합니다.

기본 추가 모드대체 모드 (-I {}) 가 있죠.


기본 모드

-I 옵션 없이 xargs를 사용할 때의 기본 동작 방식입니다.

xargs는 최대한 효율적으로 동작하는 것을 목표로 합니다. 입력을 하나씩 처리하는 대신, 가능한 많은 입력값(파일 목록 등)을 한 번에 모아서 명령어의 맨 끝에 인자로 추가합니다.

  • 🏃‍♂️ 비유: 쇼핑 목록(입력값)에 있는 물건들을 카트 하나(명령어)에 전부 담아서 한 번에 계산하는 것과 같습니다.

예시

위에서 봤던 로그 파일 삭제 예시를 다시 볼까요?

만약 a.log, b.log, c.log 파일이 발견되었다면, xargs는 다음과 같이 단 한 줄의 명령어를 만들어 실행합니다.

# xargs가 최종적으로 실행하는 명령어
rm a.log b.log c.log

rm a.log, rm b.log... 처럼 여러 번 실행하는 것보다 훨씬 빠르고 효율적입니다.


언제 사용할까?

rm, cp, docker stop, cat처럼 여러 개의 인자를 한 번에 받아 처리할 수 있는 명령어와 함께 사용할 때 가장 이상적입니다.


대체 모드 (-I)

-I {} 옵션을 사용할 때 xargs는 완전히 다르게 동작합니다.

xargs는 입력값을 한 줄(항목)씩 읽어 들여, 지정된 **대체 문자열({})**을 해당 입력값으로 바꾼 후 명령어를 실행합니다.

입력된 줄의 수만큼 명령어가 반복 실행됩니다. {}는 관례적으로 많이 사용하며, xargs -I R처럼 다른 문자를 사용해도 됩니다.

  • 👨‍🍳 비유: 레시피(입력값)에 있는 요리들을 하나씩 순서대로, 정해진 조리법(명령어)에 따라 요리하는 것과 같습니다.

예시

모든 .txt 파일의 이름 앞에 old_ 라는 접두사를 붙여서 이동(rename)시키는 작업을 해봅시다.

ls *.txt | xargs -I {} mv {} old_{}

만약 file1.txt, file2.txt가 있다면, xargs는 다음과 같이 여러 개의 명령어를 순차적으로 실행합니다.

# 첫 번째 입력값(file1.txt)으로 실행
mv file1.txt old_file1.txt

# 두 번째 입력값(file2.txt)으로 실행
mv file2.txt old_file2.txt

이런 작업은 mv file1.txt file2.txt old_file1.txt old_file2.txt 처럼 한 번에 처리할 수 없으므로, -I {} 모드가 반드시 필요합니다.


언제 사용할까?

  • 입력값을 명령어의 중간에 넣어야 할 때
  • 하나의 입력값에 대해 여러 번의 조작이 필요할 때 (... {} ... {} ...)
  • 실행할 명령어가 한 번에 하나의 인자만 처리할 수 있을 때

✨ 보너스 팁: 스크립트를 견고하게 만드는 -r 옵션

xargs를 스크립트에서 사용할 때, 파이프로 전달되는 입력이 비어있는 경우도 생길 수 있습니다.

이때 -r (또는 --no-run-if-empty) 옵션이 없다면 xargs는 인자 없이 명령어를 실행하려다 오류를 냅니다.

xargs -r은 입력이 비어있으면 아예 명령어를 실행하지 않도록 막아주는 아주 중요한 안전장치입니다.

# 습관처럼 -r을 붙여주면 스크립트가 훨씬 안전해집니다.
find . -name "*.bak" | xargs -r rm

자주 사용하는 xargs 옵션

옵션 설명
-n N 한 번에 넘길 인자 수 제한
-0 null 문자(\0) 기준 인자 처리 (-print0과 함께 사용)
-I {} 자리표시자 사용 (반복된 위치에 사용 가능)
-P N 병렬 프로세스 수
-d DELIM 사용자 지정 구분자 사용

실전 예제 모음

1. 텍스트 파일을 찾아서 내용 출력하기

find . -name "*.txt" | xargs cat
  • 현재 디렉토리 이하에서 .txt 파일을 모두 찾아
  • cat 명령어로 내용을 출력합니다.

2. 특정 문자열이 포함된 파일 찾기

find . -type f | xargs grep "에러"
  • 현재 디렉토리 이하에서 "에러"라는 문자열이 포함된 파일 내용을 출력합니다.

3. 파일 이름에 공백이 있을 때 (안전하게)

find . -type f -name "*.txt" -print0 | xargs -0 grep "오류"
  • -print0: 널 문자(\0)로 구분해서 출력
  • -0: xargs가 널 문자 기준으로 인자 구분

파일 이름에 공백, 탭, 개행 등이 있어도 안전하게 처리할 수 있습니다.


4. 자리표시자 사용하기

echo "file1.txt file2.txt" | xargs -n 1 -I {} echo "처리 중: {}"
  • -n 1: 한 번에 하나의 인자 전달
  • -I {}: 자리표시자로 {} 사용

결과:

처리 중: file1.txt
처리 중: file2.txt

5. 병렬 처리로 속도 높이기

cat urls.txt | xargs -n 1 -P 4 curl -O
  • urls.txt에 있는 파일들을 4개 병렬로 다운로드
  • -P 4: 4개의 프로세스 병렬 실행
  • -n 1: 한 줄씩 하나씩 넘김

xargs vs -exec

find 명령어에서 -exec 옵션을 사용해도 동일한 동작을 할 수 있다는거 알고 계시죠?

하지만 성능과 유연성 측면에서 xargs가 더 유리할 때가 많아요.

# -exec 사용
find . -name "*.txt" -exec cat {} \;

# xargs 사용
find . -name "*.txt" | xargs cat
  • -exec: 파일마다 명령 실행 -> 느림
  • xargs: 여러 인자를 한 번에 처리 -> 빠름
    Tag -

Loading script...