-exec를 사용하여 문자열에서 알 수 없는 문자를 탈출합니다.

-exec를 사용하여 문자열에서 알 수 없는 문자를 탈출합니다.

특정 파일과 디렉터리를 찾는 find 명령이 있습니다. 그런 다음 find 명령은 이전에 찾은 파일과 디렉터리를 소스로 사용하여 rsync를 실행합니다. 문제는 이러한 파일과 디렉터리에 Windows 등의 불법 문자는 물론 작은따옴표, 큰따옴표 등 다양한 문자가 포함될 수 있다는 것입니다.

rsync 또는 기타 명령에 사용하기 위해 문자열을 동적으로 이스케이프하려면 어떻게 해야 합니까?

이 명령은 rsync 소스 문자열에 큰따옴표를 하드 코딩하여 작동하지만 문자열에 큰따옴표가 포함되어 있으면 중단됩니다.

find "/mnt/downloads/cache/" -depth -mindepth 1 \( \
-type f \! -exec fuser -s '{}' \; -o \
-type d \! -empty \) \
\( -exec echo rsync -i -dIWRpEAXogt --numeric-ids --inplace --dry-run '"{}"' "${POOL}" \; \)

결과 출력:

rsync -i -dIWRpEAXogt --numeric-ids --inplace --dry-run "test/this " is an issue" /mnt/backing

답변의 정보를 적용한 후 작업 명령:

find "/mnt/downloads/cache/" -depth -mindepth 1 \( \
                             -type f \! -exec fuser -s {} \; -o \
                             -type d \! -empty \) \
                             \( -exec rsync -i -dIWRpEAXogt --remove-source-files-- "${POOL} \; \) \
                             -o \( -type d -empty -exec rm -d {} \; \)

답변1

귀하의 인용 문제는 귀하가 갖고 있지 않은 문제를 해결하려고 노력하는 데서 발생합니다. 매개변수 인용은 쉘을 다루는 경우에만 필요하며, 직접 find호출 하면 rsync쉘은 관련되지 않습니다. 시각적 출력을 사용하는 것은 각 매개변수의 시작과 끝을 확인할 수 없기 때문에 작동 여부를 확인하는 좋은 방법이 아닙니다.

이것이 내가 의미하는 바입니다:

# touch "foo'\"bar"

# ls
foo'"bar

# find . -type f -exec stat {} \;
  File: ‘./foo'"bar’
  Size: 0           Blocks: 0          IO Block: 4096   regular empty file
Device: fd00h/64768d    Inode: 1659137     Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1004/ phemmer)   Gid: ( 1004/ phemmer)
Access: 2017-12-09 13:21:28.742597483 -0500
Modify: 2017-12-09 13:21:28.742597483 -0500
Change: 2017-12-09 13:21:28.742597483 -0500
 Birth: -

{}arg 에서는 인용 하지 않았습니다 stat.

그러나 rsync일치하는 모든 파일을 호출하므로 명령 성능이 매우 저하됩니다. 이 문제를 해결하는 방법에는 두 가지가 있습니다.

다른 사람들이 지적했듯이 파일 목록을 rsync표준 입력으로 파이프할 수 있습니다.

# find . -type f -print0 | rsync --files-from=- -0 . dest/

# ls dest/
foo'"bar

파일 이름에는 널 바이트가 포함될 수 없으므로 파일 이름 구분 기호로 널 바이트가 사용됩니다.

 

GNU 를 사용하는 경우 를 find호출하는 또 다른 방법이 있습니다 . -exec즉, -exec {} +이 스타일에서는 find여러 인수가 한 번에 전달됩니다. 그러나 모든 매개변수는 명령 중간이 아닌 명령 끝에 추가됩니다. 작은 셸을 통해 매개변수를 전달하면 이 문제를 해결할 수 있습니다.

# find . -type f -exec sh -c 'rsync "$@" dest/' {} +

# ls dest/
foo'"bar

그러면 파일 목록이 전달된 sh다음 다음으로 대체됩니다."$@"

답변2

다음과 함께 사용하세요 find:-print0rsync --files-from=- -0

find "${Share}" -depth -mindepth 1 \( \
-type f \! -exec fuser -s '{}' \; -o \
-type d \! -empty \) -print0 | rsync --files-from=- -0 "${Share}" ${POOL}

find이제 (~로 인해)로 구분된 발견된 파일 목록이 생성됩니다 . NUL은 파일 이름에 유효한 문자가 아니므로 목록에서 구분 기호로 안전하게 사용할 수 있습니다. 목록은 표준 출력으로 인쇄되어 읽혀집니다. 일반적으로 소스 파일을 인수로 사용하지만 파일을 읽을 수도 있습니다.\0-print0rsyncrsync

find $PATH [your conditions here] -print > my-file-list.txt
rsync --files-from=my-file-list.txt $PATH $DESTINATION

물론, -print0and not을 사용했기 때문에 파일이 다음으로 구분되어 있음 -print을 알려야 합니다 .rsync\0

find $PATH [your conditions here] -print0 > my-file-list.txt
rsync --files-from=my-file-list.txt -0 $PATH $DESTINATION

-인수를 사용하여 표준 입력에서 파일을 읽어야 함을 --files-from알리고 중간 파일을 제거할 수 있습니다.rsync

find $PATH [your conditions here] -print0 \
  | rsync --files-from=- -0 $PATH $DESTINATION

경로 는 rsync여전히 소스로 필요하지만 전송만 가능합니다 find.

답변3

이 경우 정확한 인용은 매우 어렵습니다. 나는 보통 포기하고 다른 도구를 시도해 봅니다. 죄송합니다. 이것은 테스트되지 않았으며 시도할 입력이 없으므로 심각하게 깨질 수 있는 추측입니다. :) find에서 print0을 사용하여 출력을 null로 종료(공백 종료 대신)한 다음 xargs에서 -0을 사용하세요. 이런 종류의 입력을 기대합니다... 이는 포함된 공백이 깨지는 것을 방지하기 위한 것입니다.

find "${Share}" -depth -mindepth 1 \( \
-type f \! -exec fuser -s '{}' \; -o \
-type d \! -empty \) -print0 | \
xargs -0 -I{} rsync -i -dIWRpEAXogt --numeric-ids --inplace --dry-run {} ${POOL}

관련 정보