stdin 입력이 비어 있으면 xargs 명령을 무시하는 방법은 무엇입니까?


189

이 명령을 고려하십시오.

ls /mydir/*.txt | xargs chown root

모든 텍스트 파일의 소유자 mydir를 루트 로 변경하는 것이 목적입니다.

문제는 .txt파일 이 없으면 mydirxargs는 경로가 지정되지 않았다는 오류를 발생시키는 것입니다. 이것은 오류가 발생하기 때문에 무해한 예이지만, 여기에서 사용해야하는 스크립트와 같은 경우 빈 경로가 현재 디렉토리로 간주됩니다. 따라서 그 명령을 실행 /home/tom/하면 결과가없고 ls /mydir/*.txt모든 파일 /home/tom/의 소유자가 root로 변경되었습니다.

xargs가 빈 결과를 무시하도록 어떻게 할 수 있습니까?


6
따로 : ls프로그램 용도로 출력을 배관하지 마십시오 . mywiki.wooledge.org/ParsingLs
Charles Duffy를

내 유스 케이스는 git branch --merged | grep -v '^* ' | xargs git branch -d입니다. 빈 입력에서도 실패합니다.
belkka

답변:


305

GNU의 xargs경우 -r또는 --no-run-if-empty옵션을 사용할 수 있습니다 .

--no-run-if-empty
-r
표준 입력에 비 공백이 없으면 명령을 실행하지 마십시오. 일반적으로 입력이없는 경우에도 명령이 한 번 실행됩니다. 이 옵션은 GNU 확장입니다.


9
나는 정직하게 구글에서 먼저 검색하고 이것을 발견했다 (그러나 매뉴얼을 읽지 않고 묻지 않았을 것이다). 나는 이것이 기본 동작이 될 것이라고 생각했는데, 스위치를 활성화 할 필요가 없습니다.
JonnyJD

28
불행히도 이것은 Mac에서 작동하지 않습니다. 짧거나 긴 옵션은 아닙니다.
wedi

9
@wedi-OSX에는 BSD 사용자 공간이 있으므로 이런 일이 자주 발생합니다. homebrew를 사용하여 GNU fileutils를 설치하면이 문제를 해결할 수 있습니다.
edk750

7
당신은 의미 brew install findutils합니다. findutils아닙니다 fileutils.
Mitar

3
macOS에서는 플래그를 제공하지 않으면 어쨌든 명령이 실행되지 않으므로 필요하지 않은 것 같습니다.
Trejkaz

15

비 GNU의 xargs를의 사용자 이용의 걸릴 수 있습니다 -L <#lines>, -n <#args>, -i, 및 -I <string>:

ls /empty_dir/ | xargs -n10 chown root # chown executed every 10 args or fewer
ls /empty_dir/ | xargs -L10 chown root # chown executed every 10 lines or fewer
ls /empty_dir/ | xargs -i cp {} {}.bak # every {} is replaced with the args from one input line
ls /empty_dir/ | xargs -I ARG cp ARG ARG.bak # like -i, with a user-specified placeholder

xargs는 공백으로 줄을 나누지 만 인용 및 이스케이프는 가능합니다. 자세한 내용은 RTFM을 참조하십시오.

또한 Doron Behar가 언급했듯이이 해결 방법은 이식성이 없으므로 확인이 필요할 수 있습니다.

$ uname -is
SunOS sun4v
$ xargs -n1 echo blah < /dev/null
$ uname -is
Linux x86_64
$ xargs --version | head -1
xargs (GNU findutils) 4.7.0-git
$ xargs -n1 echo blah < /dev/null
blah

2
질문에 대답하지 않는 것 같습니까?
Nicolas Raoul

2
@Nicolas : 버전이 스위치를 xargs지원 --no-run-if-empty하지 않고 STDIN 입력없이 명령 인수를 실행하려고 시도하는 경우 실행을 방지하는 방법입니다 (Solaris 10의 경우). 다른 유닉스 버전은 빈 목록 (예 : AIX)을 무시할 수 있습니다.
arielCo

4
예! MAC OSX echo '' | xargs -n1 echo blah에서는 아무 것도 수행하지 않습니다. 반면 echo 'x' | xargs -n1 echo blah"blah"를 인쇄합니다.
carlosayam

2
GNU 및 BSD / OSX 지원 모두에 대해 다음과 같은 ls /mydir/*.txt | xargs -n 1 -I {} chown root {}결과를 얻습니다.
루이스 비안 친

3
GNU로 echo '' | xargs -n1 echo blah인쇄 한다는 점에 유의해야합니다 . blahxargs
Doron Behar

11

man xargs말한다 --no-run-if-empty.


1
OSX를 사용하는 경우에는 그렇지 않습니다. edk750은 왜 당신이 궁금하다면 그들의 의견에 이것을 설명했습니다.
jasonleonhard

9

의 관점에서 제안 된대로 xargs사용할 수 -r있지만 BSD에서는 지원하지 않습니다 xargs.

따라서 임시 해결책으로 다음과 같은 추가 임시 파일을 전달할 수 있습니다.

find /mydir -type f -name "*.txt" -print0 | xargs -0 chown root $(mktemp)

또는 stderr을 null ( 2> /dev/null) 로 리디렉션하십시오.

find /mydir -type f -name "*.txt" -print0 | xargs -0 chown root 2> /dev/null || true

또 다른 더 좋은 방법은 while루프를 사용하여 찾은 파일을 반복하는 것입니다.

find /mydir -type f -name "*.txt" -print0 | while IFS= read -r -d '' file; do
  chown -v root "$file"
done

참조 : 맥 OS X에서 xargs를 빈 결과를 무시


또한 권한을 변경하는 방법이 훌륭하지 않으며 권장하지 않습니다. 분명히 ls명령 의 출력을 구문 분석해서는 안됩니다 (ls 출력을 구문 분석해서는 안되는 이유 참조 ). 특히 루트로 명령을 실행하는 경우 파일은 쉘에서 해석 할 수있는 특수 문자로 구성되거나 주위에 공백 문자가있는 파일을 상상할 /수 있으므로 결과가 끔찍할 수 있습니다.

따라서 접근 방식을 변경하고 find대신 명령을 사용해야 합니다. 예 :

find /mydir -type f -name "*.txt" -execdir chown root {} ';'

1
죄송합니다, 어떻게 while IFS= read -r -d '' file유효한지 이해할 수 없습니다 . 설명 할 수 있습니까?
Adrian

2

OSX : 인수 를 xargs처리하는 Bash 재 구현 -r, 예를 들어 다음에 $HOME/bin추가하십시오 PATH.

#!/bin/bash
stdin=$(cat <&0)
if [[ $1 == "-r" ]] || [[ $1 == "--no-run-if-empty" ]]
then
    # shift the arguments to get rid of the "-r" that is not valid on OSX
    shift
    # wc -l return some whitespaces, let's get rid of them with tr
    linecount=$(echo $stdin | grep -v "^$" | wc -l | tr -d '[:space:]') 
    if [ "x$linecount" = "x0" ]
    then
      exit 0
    fi
fi

# grep returns an error code for no matching lines, so only activate error checks from here
set -e
set -o pipefail
echo $stdin | /usr/bin/xargs $@

2

이것은 -r, --no-run-if-empty를 사용하여 억제 할 수있는 GNU xargs의 동작입니다.

xargs의 * BSD 변형에는 기본적으로이 동작이 있으므로 -r이 필요하지 않습니다. FreeBSD 7.1 이후 (2009 년 1 월에 릴리스), 호환성 이유로 -r 인수가 허용됩니다 (스위치는 아무것도하지 않습니다).

필자는 개인적으로 스크립트에서 longopts를 선호하지만 * BSD xargs는 longopts를 사용하지 않기 때문에 "-r"만 사용하고 xargs는 * BSD와 Linux 시스템에서 동일하게 작동합니다.

MacOS (현재 MacOS Mojave)의 xargs는 "-r"인수를 지원하지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.