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
).