"xargs" 및 "file"에 대한 이상한 "해당 파일 없음" 오류

"xargs" 및 "file"에 대한 이상한 "해당 파일 없음" 오류

현재 디렉토리에 있는 모든 파일의 MIME 유형을 얻고 싶습니다. 왜 이것이 작동하지 않습니까? OSX 또는 Linux에서 bash를 테스트했습니다. "file"은 파일을 찾을 수 없다고 불평하지만, 정확히 동일한 경로를 사용하여 실행하면 작동합니다.

$ find . -type f | xargs -n 1 -I FILE echo $(file --mime-type -b FILE)
ERROR: cannot open './foo.txt' (No such file or directory)
...
$ file --mime-type -b ./foo.txt
text/plain

물론 실제 세계에서는 응답을 "에코"하는 것이 아니라 다른 명령에서 MIME 유형 문자열을 사용해야 합니다.

이것이 제가 해결할 수 있는 가장 간단한 문제입니다. 파일 이름 대체에 대해 뭔가 이해하지 못하는 것 같나요 xargs?

답변1

명령 대체는 $(file --mime-type -b FILE)에 전달되기 전에 쉘에 의해 수행되므로 xargs필요한 것이 표시되지 않습니다. xargs를 통해 인용하고 $(file --mime-type -b FILE)전달하십시오.bash -c

find . -type f | xargs -n 1 -I FILE bash -c  'echo $(file --mime-type -b FILE)'

답변2

여기서는 악용할 필요가 없습니다 xargs. find스위치를 사용하면 됩니다 -exec.

$ find . -type f -exec file --mime-type -- {} +

기본 file출력

$ find 8* -type f -exec file --mime-type -- {} + | tail -5
89999/sample10.txt:               text/plain
89999/sample2.txt:                text/plain
89999/sample4.txt:                text/plain
89999/sample6.txt:                text/plain
89999/sample9.txt:                text/plain

file -b산출

$ find 8* -type f -exec file --mime-type -b -- {} + | head -5
application/x-empty
text/x-perl
text/plain
text/plain
text/plain

대안

mimetype이는 단지 참조용일 뿐이지 만 동일한 작업을 수행하는 데 사용할 수도 있는 또 다른 명령이 있습니다 file --mimetype. 이 명령은 Fedora에서 이 패키지의 일부 perl-File-MimeInfo이며 유사하게 작동합니다.

$ find 8* -type f -exec mimetype -- {} + | tail -5
89999/sample10.txt:               text/plain
89999/sample2.txt:                text/plain
89999/sample4.txt:                text/plain
89999/sample6.txt:                text/plain
89999/sample9.txt:                text/plain

보다 자세한 구현

"단지 echo.. 이상"에 대해 질문하셨고, ..를 사용하려고 하신다는 점을 고려하면, ..을 xargs사용해야 한다고 생각하신다는 결론을 내리겠습니다 xargs.

그러나 를 사용하는 경우 find이는 일반적으로 최선의 접근 방식이 아닙니다. 더 복잡한 방법으로 이 작업을 수행하는 대신 스위치 find에서 셸을 사용 하고 호출하여 거기서 더 복잡한 작업을 수행 할 수 있습니다.find-execxargs

$ find . -type f -exec sh -c '
   cmd1;
   cmd2;
   file --mime-type -b "$@";
   cmd3;
   cmd4;
 ' sh {} \;

노트:+여러 매개변수를 전달하는 종결자를 사용하는 것에서 file --mime-type ...한 번에 하나의 매개변수를 전달하는 것으로 전환했습니다 \;.

$ find 8* -type f -exec sh -c '
   echo -n "mime-type: "; 
   file --mime-type -b "$@"
  ' sh {} \; |& tail -10
mime-type: text/plain
mime-type: text/plain
mime-type: text/plain
mime-type: text/plain
mime-type: text/x-shellscript
mime-type: text/plain
mime-type: text/plain
mime-type: text/plain
mime-type: text/plain
mime-type: text/plain

답변3

귀하의 문제는 쉘 확장과 관련이 있습니다. $()는 인수로 전달되기 전에 확장됩니다. 있는 그대로 처리하려면 작은따옴표로 묶고 쉘을 호출하세요.

또한 파일 이름을 다루는 경우 print0과 0을 사용하는 습관을 들이십시오. 이를 생략하면 공백 문자가 포함된 파일 이름에 문제가 발생할 수 있습니다.

예:

find . -type f -print0 | xargs -0 -n 1 -I FILE bash -c 'echo $(file --mime-type -b FILE)'

귀하의 경우 이는 다음과 같이 단순화될 수 있습니다.

find . -type f -print0 | xargs -0 -n 1 file --mime-type -b

추가 설명: 발견된 모든 파일("xargs -n 1" 또는 find+exec)에 대해 프로그램을 호출하면 실제 성능 병목 현상이 발생할 수 있습니다. 디렉터리에 수천 개의 파일이 포함되어 있으면 수천 개의 프로세스가 생성됩니다.

관련 정보