파이핑 결과 출력 시 이상한 경로 문자를 처리하는 방법은 무엇입니까?

파이핑 결과 출력 시 이상한 경로 문자를 처리하는 방법은 무엇입니까?

명령에서 각 경로의 길이를 찾고 싶은 문제가 있습니다 find. 나의 첫 번째 시도는 다음과 같은 것을 실행하는 것이 었습니다.

find . -exec sh -c "echo {} | wc -c" \;

이 답변에서 아이디어를 얻었습니다.. (위 명령은아니요내 문제는 단지 예를 들기 위한 것인데, 그것이 완전히 인공적이라는 것입니다. 또한 때로는 여러 개의 파이프가 필요할 수도 있습니다. )

하지만 실행하면 출력 경로에 있는 특수 문자로 인해 출력에 오류가 발생합니다. 안타깝게도 어떤 경로가 문제를 일으키는지 해결하는 방법을 모르며 오류 메시지에는 어떤 정보도 제공되지 않습니다. 에도 불구하고...

나중에 이 답변을 우연히 발견했습니다.:

명령은 find명령을 직접 실행합니다. 이 명령(filename 인수 포함)은 셸이나 파일 이름을 수정할 수 있는 다른 항목에 의해 처리되지 않습니다. 매우 안전합니다.

이것은 매우 편리한 것 같습니다. 사실 너무 편리해서 -exec sh -c ..."치료"가 질병 자체보다 더 나쁜 것처럼 보입니다.

그래서 내 질문은, 내가 언제필요파이프 명령 find과 내 경로에 특수 문자가 포함될 수 있나요?이 문제에 대한 보편적인 해결책이 있습니까?여러 가지 고려 사항을 생각할 필요가 없나요? 나는 배쉬를 사용하고 있습니다.


참고: 이것은 비슷한 질문입니다.find + exec 명령의 출력을 파이프로 보내는 가장 좋은 방법은 무엇입니까?차이점은 출력을 반드시 -exec. find ... -exec ... foo {} | bar \;나는 저항이 가장 적은 공통 경로를 찾고 있을 뿐이며 명령의 구조는 나에게 중요하지 않습니다.

답변1

파일 이름을 쉘 스크립트에 인수로 전달하십시오.

find . -exec sh -c 'printf "%s\n" "$1" | wc -c' sh {} \;

또는 쉘당 여러 파일을 호출합니다.

find . -exec sh -c 'for x in "$@"; do printf "%s\n" "$x" | wc -c; done' sh {} +

주문

find . -exec sh -c "echo {} | wc -c" \;

파일 이름은 쉘 명령줄에 그대로 삽입됩니다. 공백이나 쉘 특정 문자가 포함되지 않은 파일 이름에만 작동합니다. 예를 들어, Don't stop me now.mp3같은 것은 this&that.txt문제를 일으킬 수 있습니다. (첫 번째는 끝나지 않은 인용 문자열을 생성하고, 두 번째는 echo백그라운드에서 시작된 다음 이름이 지정된 명령을 실행하려고 시도합니다 that.txt.)

반면에 sh -c ... sh {} \;(또는 파일 이름이 다른 인수로 쉘에 전달 ... {} +find경우 위치 인수에서 사용할 수 있으며 쉘 구문과 혼합하지 않고 사용할 수 있습니다. ( "$1"첫 번째의 경우 "$@"전체에 대해) 목록 .)

파일 이름 길이를 확인하는 경우 "${#var}"길이를 다음과 같이 제공하는 것을 제외하고 셸에서 가져올 수도 있습니다.수치현재 로케일을 기준으로 동시에 wc -c계산바이트.

답변2

-exec echo {}피하고 있음에도 불구하고껍데기처리, 여러 버전에코mangle 매개변수에는 백슬래시 또는 선행 하이픈이 포함됩니다. (물론 wc원하는대로 전송되지는 않습니다.)

모든 경로명에 대해 이 작업을 수행하는 대신 wc여러 입력 줄(레코드라고도 함)을 처리하도록 설계된 프로그램을 사용하겠습니다.

find . | awk '{print length}'   # basecase

# if in a multibyte locale and you want bytes not chars
# prefix the awk with LANG=C (or any other singlebyte)

# if pathname (ever) contains newline, and you have GNU find (and awk?)
find . -print0 | awk -vRS='\0' '{print length}' 

또는 기본값은 바이트이지만 개행이 허용되는 경우를 perl -nle 'print length'처리하는 방법을 찾지 못했습니다 .-print0

관련 정보