리눅스 환경에서 여러 명령어를 함께 사용해야 할 때, 일부 명령어는 파이프 입력을 직접적으로 허용하지 않는 경우가 있습니다. 이때 xargs
명령어를 사용하면 한 명령어의 출력을 다른 명령어의 인수로 전달하여 이러한 제약을 극복할 수 있습니다. xargs
는 표준 입력 스트림을 활용하여 명령어를 연결하고 복잡한 작업을 자동화하는 데 유용한 도구입니다.
모든 표준 리눅스 유틸리티는 세 가지 주요 데이터 스트림을 가지고 있습니다. 바로 표준 입력(stdin), 표준 출력(stdout), 표준 에러(stderr)입니다. 이러한 스트림은 텍스트 기반으로 작동하며, 표준 입력 스트림은 명령어로 데이터를 전달하고, 표준 출력 스트림은 터미널 창에 명령의 결과를 텍스트 형태로 표시합니다. 오류 메시지는 표준 에러 스트림을 통해 터미널 창에 텍스트 형태로 나타납니다.
리눅스 및 유닉스 계열 운영체제의 뛰어난 기능 중 하나는 한 명령어의 표준 출력(stdout)을 다른 명령어의 표준 입력(stdin)으로 연결하는 파이프 기능입니다. 이렇게 하면 첫 번째 명령어는 출력 방향을 신경 쓰지 않고, 두 번째 명령어는 입력이 키보드가 아닌 다른 명령어에서 온다는 것을 알 필요 없이 작업을 수행할 수 있습니다. 하지만 모든 리눅스 명령어가 다른 명령어의 표준 출력을 표준 입력으로 받아들일 수 있는 것은 아닙니다. 즉, 일부 명령어는 파이프 입력을 직접적으로 사용할 수 없습니다.
xargs
는 바로 이러한 상황에서 표준 데이터 스트림을 사용하여 실행 파이프라인을 구성하는 데 사용되는 명령어입니다. xargs
를 활용하면 echo
, rm
, mkdir
등과 같이 표준 입력을 인수로 직접 받을 수 없는 명령어들도 파이프 입력을 받아 처리할 수 있게 됩니다.
xargs 명령어 기본 작동 원리
xargs
명령어는 파이프 입력을 받거나, 파일에서 입력을 읽어들일 수 있습니다. 그런 다음, 입력된 데이터를 사용자가 지정한 명령의 인수로 전달합니다. 만약 특정 명령어를 지정하지 않으면 기본적으로 echo
명령어를 사용하여 입력된 데이터를 출력합니다. xargs
는 여러 줄의 입력이 주어져도 항상 한 줄의 출력을 생성한다는 특징을 가지고 있습니다.
ls
명령어와 함께 -1
옵션(한 줄에 하나의 파일 나열)을 사용하여 파일 이름을 한 줄씩 출력할 수 있습니다.
ls -1 ./*.sh
위 명령어는 현재 디렉토리의 모든 쉘 스크립트 파일 목록을 보여줍니다.
보시는 바와 같이, 파일 목록이 한 줄씩 출력됩니다. 이제 이 출력을 xargs
로 파이프하면 어떻게 될까요?
ls -1 ./*.sh | xargs
결과적으로 파일 이름들이 하나의 긴 텍스트 스트림으로 터미널에 출력됩니다.
바로 이 기능이 xargs
가 다른 명령어에 인수를 전달하는 기본 원리입니다.
wc 명령어와 함께 xargs 사용
xargs
를 사용하여 wc
명령어로 여러 파일의 단어, 문자, 라인 수를 쉽게 계산할 수 있습니다.
ls *.page | xargs wc
위 명령어는 다음과 같은 과정을 거칩니다:
ls
명령어는*.page
파일 목록을 생성하고xargs
로 전달합니다.xargs
는 파일 이름을wc
명령어에 전달합니다.wc
명령어는 파일 이름을 명령줄 인수로 받아들여 각 파일의 단어, 문자, 라인 수를 계산합니다.
각 파일에 대한 통계와 함께 전체 합계가 표시됩니다.
확인 메시지와 함께 xargs 사용
-p
(대화형) 옵션을 사용하면 xargs
가 작업을 진행하기 전에 확인 메시지를 표시하도록 설정할 수 있습니다. xargs
를 통해 파일 이름 문자열을 touch
명령어에 전달하면, touch
는 해당 이름의 파일을 생성합니다.
echo 'one two three' | xargs -p touch
위 명령어를 실행하면 실행될 명령어(touch one two three
)가 표시되고, xargs
는 사용자가 “y” 또는 “Y”, “n” 또는 “N”을 입력하고 Enter 키를 누를 때까지 기다립니다.
Enter 키만 누르면 “n”으로 처리되며, “y” 또는 “Y”를 입력해야만 명령어가 실행됩니다.
“y”를 누르고 Enter 키를 누르면 파일이 생성됩니다. ls
명령어로 생성된 파일을 확인할 수 있습니다.
ls one two three
여러 명령어와 함께 xargs 사용
-I
(초기 인수) 옵션을 사용하면 xargs
와 함께 여러 명령어를 조합하여 사용할 수 있습니다. 이 옵션은 “replace-string”을 정의합니다. 이 문자열이 명령어 줄에 나타날 때마다 xargs
에 제공된 값이 삽입됩니다.
tree
명령어를 사용하여 현재 디렉토리의 하위 디렉토리를 살펴보겠습니다. -d
(디렉토리) 옵션은 파일은 무시하고 디렉토리에 대해서만 출력하도록 합니다.
tree -d
현재 디렉토리에는 “이미지”라는 하나의 하위 디렉토리가 존재합니다.
“directories.txt” 파일에는 만들고자 하는 여러 디렉토리 이름이 저장되어 있습니다. cat
명령어로 파일 내용을 확인할 수 있습니다.
cat directories.txt
이제 이 파일 내용을 xargs
의 입력 데이터로 사용합니다. 우리가 사용할 명령어는 다음과 같습니다.
cat directories.txt | xargs -I % sh -c 'echo %; mkdir %'
위 명령어는 다음과 같이 나눌 수 있습니다.
cat directories.txt |
:directories.txt
파일의 내용(새 디렉토리 이름들)을xargs
로 전달합니다.xargs -I %
: “%” 토큰을 “replace-string”으로 정의합니다.sh -c
: 새로운 서브쉘을 시작합니다.-c
옵션은 쉘이 명령줄에서 명령어를 읽도록 지시합니다.'echo %; mkdir %'
: 각 “%” 토큰은xargs
에 의해 전달된 디렉토리 이름으로 대체됩니다.echo
명령어는 디렉토리 이름을 출력하고,mkdir
명령어는 디렉토리를 생성합니다.
디렉토리 이름이 하나씩 출력됩니다.
tree -d
명령어로 디렉토리가 생성되었는지 다시 한번 확인할 수 있습니다.
tree -d
여러 위치에 파일 복사
xargs
를 사용하면 단일 명령으로 파일을 여러 위치에 복사할 수 있습니다. 두 디렉토리 이름을 입력 매개변수로 xargs
에 파이프하고, 한 번에 매개변수 하나씩만 xargs
가 처리하도록 설정합니다. 이 경우 명령어는 cp
이며, 결과적으로 각 디렉토리마다 cp
명령어가 한 번씩 실행됩니다. 이를 가능하게 하는 xargs
옵션은 -n
(최대 인수 개수)이며, 이 옵션을 1로 설정합니다.
또한 cp
명령어에 -v
(verbose) 옵션을 추가하여 복사 작업 과정을 출력하도록 설정합니다.
echo ~/Backups/ ~/Documents/page-files/ | xargs -n 1 cp -v ./*.page
파일이 한 번에 한 디렉토리씩, 두 디렉토리에 복사됩니다. cp
명령어는 각 복사 작업을 출력하여 진행 상황을 확인할 수 있습니다.
중첩 디렉토리에서 파일 삭제
파일 이름에 공백이나 개행 문자와 같은 특수 문자가 포함되어 있을 경우, xargs
는 이를 제대로 해석하지 못할 수 있습니다. -0
(null terminator) 옵션을 사용하여 이 문제를 해결할 수 있습니다. 이 옵션은 xargs
가 파일 이름의 최종 구분 기호로 null 문자를 사용하도록 지시합니다.
이 예제에서는 find
명령어를 사용합니다. find
명령어에도 자체 옵션이 있어 파일 이름의 공백이나 특수 문자를 처리할 수 있습니다. 바로 -print0
(전체 이름, null 문자) 옵션입니다.
find . -name "*.png" -type f -print0 | xargs -0 rm -v -rf "{}"
위 명령어는 다음과 같이 나눌 수 있습니다.
find . -name "*.png" -type f
:find
명령어는 현재 디렉토리(.
)에서*.png
와 이름이 일치하는 파일(-type f
)을 검색합니다.-print0
: 파일 이름은 null 문자로 끝나며, 공백과 특수 문자는 올바르게 처리됩니다.xargs -0
:xargs
명령어 역시 파일 이름이 null 문자로 끝난다고 가정하고, 공백과 특수 문자로 인한 오류를 피합니다.rm -v -rf "{}"
:rm
명령어는 자세한 작업 내용을 출력하고(-v
), 재귀적으로(-r
) 하위 디렉토리를 탐색하며, 확인 없이(-f
) 파일을 삭제합니다."{}"
는 각 파일 이름으로 대체됩니다.
위 명령어는 모든 하위 디렉토리를 검색하여 지정된 패턴과 일치하는 파일을 삭제합니다.
중첩 디렉토리 삭제
이제 중첩된 하위 디렉토리들을 삭제하는 방법을 살펴보겠습니다. tree -d
명령어를 사용하여 삭제 전 디렉토리 구조를 확인합니다.
tree -d
find
명령어를 사용하여 level_one
이라는 이름의 디렉토리를 검색하고, xargs
를 통해 rm
명령어로 전달하여 삭제합니다.
find . -name "level_one" -type d -print0 | xargs -0 rm -v -rf "{}"
위 명령어는 find
명령어를 사용하여 현재 디렉토리 내에서 재귀적으로 검색하고, level_one
이라는 이름을 가진 디렉토리를 찾습니다. 이 디렉토리 이름들은 xargs
를 통해 rm
명령어로 전달됩니다.
이전 명령어와 비교했을 때 주요 변경 사항은 검색어가 최상위 디렉토리 이름이며, -type d
옵션이 find
에게 파일이 아닌 디렉토리를 찾도록 지시한다는 점입니다.
삭제되는 각 디렉토리의 이름이 출력됩니다. tree -d
명령어로 삭제 결과를 확인할 수 있습니다.
tree -d
중첩된 모든 하위 디렉토리가 성공적으로 삭제되었습니다.
특정 파일 형식을 제외한 모든 파일 삭제
find
, xargs
, rm
명령어를 조합하여 특정 파일 형식만 제외하고 모든 파일을 삭제할 수도 있습니다. 주의할 점은 삭제하려는 파일 형식이 아니라 유지하려는 파일 형식을 지정해야 한다는 것입니다.
-not
옵션은 find
가 지정된 패턴과 일치하지 않는 파일 이름을 반환하도록 지시합니다. 여기서 -I
(초기 인수) 옵션을 다시 사용하며, 이번에는 교체 문자열 토큰을 "{}"
로 설정합니다. 이는 이전에 사용했던 %
와 동일하게 작동합니다.
find . -type f -not -name "*.sh" -print0 | xargs -0 -I {} rm -v {}
ls
명령어로 결과를 확인하면, 디렉토리에는 *.sh
패턴과 일치하는 파일들만 남아 있는 것을 볼 수 있습니다.
ls -l
Xargs를 사용하여 아카이브 파일 생성
find
명령어로 파일을 검색하고 xargs
를 통해 tar
명령어로 전달하여 아카이브 파일을 만들 수 있습니다. 현재 디렉토리에서 *.page
패턴과 일치하는 파일을 검색합니다.
find ./ -name "*.page" -type f -print0 | xargs -0 tar -cvzf page_files.tar.gz
아카이브 파일이 생성될 때 파일 목록이 예상대로 출력됩니다.
데이터 중재자로서의 Xargs
때로는 복잡한 작업을 자동화할 때 데이터를 처리하고 연결하는 데 추가적인 도구가 필요할 수 있습니다. xargs
는 정보를 출력하는 명령어와 정보를 입력으로 받도록 설계되지 않은 명령어 사이의 간극을 메우는 역할을 합니다. xargs
와 find
명령어 모두 매우 다양한 옵션을 가지고 있으므로, 더 자세한 내용은 각 명령어의 매뉴얼 페이지를 참조하는 것이 좋습니다.