파일이 존재하는지 확인한 후 파일 이름 목록을 xargs에 전달하는 방법은 무엇입니까?

파일이 존재하는지 확인한 후 파일 이름 목록을 xargs에 전달하는 방법은 무엇입니까?

command1아래와 같이 파일 이름 목록을 반환하는 명령( )이 있습니다.

/consumer/a.txt
/consumer/b.txt
/consumer/doesnotexist.txt

출력을 파이프할 때 command1 | xargs command2 command2파일 중 하나가 없으면 예외가 발생합니다.

존재하지 않는 파일을 파이핑하기 전에 어떻게 삭제할 수 있습니까 command2? 나는 다음을 기대하고 있습니다

command1 | xargs remove_nonexistant_files | xargs command2

command2받아야 한다

/consumer/a.txt
/consumer/b.txt

입력으로.

답변1

command1 |
xargs sh -c 'for p do [ -f "$p" ] && printf "%s\n" "$p"; done' sh |
xargs command 2

중간에 있는 추가 비트는 xargs기본적으로 주어진 명령줄 인수를 반복하고 기존 일반 파일(또는 일반 파일에 대한 심볼릭 링크)에 해당하는 경로 이름을 인쇄하는 짧은 스크립트에 대한 또 다른 호출입니다. 그러면 이러한 기존 경로 이름이 파이프라인의 마지막 부분에 전달됩니다.

이는 모든 경로 이름에 새 줄, 공백 및 탭이 포함되어 있지 않다고 가정합니다.

답변2

command1목록이 원하는 형식으로 출력된다고 가정하면 xargs다음을 정의할 수 있습니다.

existing_plain_readable_files_only() {
  perl -le "for (@ARGV) {
    if (-f && -r) {s/'/'\\\\''/g; print qq('\$_')}
  }" -- "$@"
}

다음과 같이 사용하십시오.

command1 | xargs existing_plain_readable_files_only | xargs command2

perl여기서는 ' -f연산자 를 사용합니다.정기적인-r파일만(디렉토리, 장치, 파이프 는 제외)읽을 수 있는사용자가( command2읽기를 원한다고 가정) 우리는 이스케이프된 작은따옴표 문자 자체를 제외하고 작은따옴표를 사용합니다 \.

xargs이는 모든 셸에서 지원되는 참조입니다. 즉, 이 함수를 사용하여 임의의 파일 목록이 포함된 셸 배열을 처리할 수도 있습니다.

eval "array2=($(existing_plain_readable_files_only "${array1[@]}"))"

(이것은 ksh93, zsh, bash또는 쉘 mksh을 가정합니다 yash).

관련 정보