"mv: 인수 목록이 너무 김" 문제를 해결하시겠습니까?

"mv: 인수 목록이 너무 김" 문제를 해결하시겠습니까?

mv정렬이 필요한 파일이 백만 개가 넘는 폴더가 있는데 항상 이 메시지가 출력되기 때문에 아무것도 할 수 없습니다.

-bash: /bin/mv: Argument list too long

확장자가 없는 파일을 이동하려면 다음 명령을 사용합니다.

mv -- !(*.jpg|*.png|*.bmp) targetdir/

답변1

xargs작업을 위한 도구입니다. 그거 아니면find와 함께 -exec … {} +. 이러한 도구는 한 번에 전달할 수 있는 만큼의 인수를 사용하여 명령을 여러 번 실행합니다.

두 방법 모두 가변 인수 목록이 끝에 있을 때 수행하기가 더 쉽지만 여기서는 그렇지 않습니다. 최종 인수가 mv대상입니다. GNU 유틸리티(예: 내장되지 않은 Linux 또는 Cygwin)의 경우 대상을 먼저 전달하는 -t옵션이 유용합니다.mv

파일 이름에 공백이나 공백이 없고 ¹ \"'으로 시작하지 않는 경우 -간단히 파일 이름을 입력으로 제공할 수 있습니다 xargs( echo명령은 bash 내장이므로 명령줄 길이 제한이 적용되지 않습니다. 이 표시되면 ) !: event not found을 사용하여 globbing 구문을 활성화해야 합니다 shopt -s extglob.

echo !(*.jpg|*.png|*.bmp) | xargs mv -t targetdir --

-0옵션을 사용하면 xargs기본 인용 형식 대신 널로 구분된 입력을 사용할 수 있습니다 .

printf '%s\0' !(*.jpg|*.png|*.bmp) | xargs -0 mv -t targetdir --

또는 를 사용하여 파일 이름 목록을 생성할 수 있습니다 find. 하위 디렉터리로 반복되는 것을 방지하려면 -type d -prune. 나열된 이미지 파일에 대해 지정된 작업이 없으므로 다른 파일만 이동됩니다.

find . -name . -o -type d -prune -o \
       -name '*.jpg' -o -name '*.png' -o -name '*.bmp' -o \
       -exec mv -t targetdir/ {} +

(여기에는 쉘 와일드카드 방법과 달리 도트 파일이 포함됩니다.)

GNU 유틸리티가 없으면 중간 쉘을 사용하여 인수를 올바른 순서로 가져올 수 있습니다. 이 방법은 모든 POSIX 시스템에서 작동합니다.

find . -name . -o -type d -prune -o \
       -name '*.jpg' -o -name '*.png' -o -name '*.bmp' -o \
       -exec sh -c 'mv "$@" "$0"' targetdir/ {} +

zsh에서는 다음을 로드할 수 있습니다.mv내장:

setopt extended_glob
zmodload zsh/files
mv -- ^*.(jpg|png|bmp) targetdir/

mv또는 다른 이름이 외부 명령을 계속 참조하도록 하려는 경우 :

setopt extended_glob
zmodload -Fm zsh/files b:zf_\*
zf_mv -- ^*.(jpg|png|bmp) targetdir/

또는 ksh 스타일 글로브를 사용하여:

setopt ksh_glob
zmodload -Fm zsh/files b:zf_\*
zf_mv -- !(*.jpg|*.png|*.bmp) targetdir/

또는 GNU를 사용 mv하여zargs:

autoload -U zargs
setopt extended_glob
zargs -- ./^*.(jpg|png|bmp) -- mv -t targetdir/ --

¹ 일부 xargs구현에서는 파일 이름도 현재 로케일에서 유효한 텍스트여야 합니다. 일부는 _입력 끝을 나타내는 파일 이름을 고려하기도 합니다 ( 로 피할 수 있음 -E '').

답변2

Linux 커널로 작업하는 것으로 충분하다면 간단히 할 수 있습니다

ulimit -S -s unlimited

이는 Linux 커널에 약 10년 전에 스택 크기에 따라 인수 제한을 변경한 패치가 포함되었기 때문에 작동할 것입니다.https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b6a2fea39318e43fee84fa7b0b90d68bed92d2ba

무제한 스택 공간을 원하지 않으면 다음과 같이 말할 수 있습니다.

ulimit -S -s 100000

스택을 100MB로 제한합니다. 스택 공간을 일반 스택 사용량(일반적으로 8MB)과 사용하려는 명령줄 크기로 설정해야 합니다.

다음과 같이 실제 한도를 쿼리할 수 있습니다.

getconf ARG_MAX

그러면 최대 명령줄 길이가 바이트 단위로 출력됩니다. 예를 들어, Ubuntu 기본값은 2097152대략 2MB를 의미하는 것으로 설정됩니다. 무제한 스택으로 실행하면 4611686018427387903정확히 2^62 또는 약 46000TB가 됩니다. 명령줄이 다음을 초과하는 경우저것, 귀하가 직접 문제를 해결할 수 있을 것으로 기대합니다.

실행 sudo중에 as를 사용하면 실제로 실행하기 전에 스택 크기를 재설정하므로 해당 문제를 해결할 수 없습니다 . 이 문제를 해결하려면 를 사용하여 루트 셸을 시작한 다음 해당 루트 셸 없이 명령을 실행하고 마지막으로 실행해야 합니다 .sudo mv *.dat somewhere/.ulimitsudomvsudo -sulimit -S -s unlimitedsudo

답변3

때로는 간단한 스크립트(예: Python)를 작성하는 것이 가장 쉽습니다.

import glob, shutil

for i in glob.glob('*.jpg'):
  shutil.move(i, 'new_dir/' + i)

답변4

운영 체제의 인수 전달 제한은 쉘 인터프리터 내에서 발생하는 확장에는 적용되지 않습니다. 따라서 xargsor 를 사용하는 것 외에도 find쉘 루프를 사용하여 처리를 개별 명령으로 나눌 수 있습니다 mv.

for x in *; do case "$x" in *.jpg|*.png|*.bmp) ;; *) mv -- "$x" target ;; esac ; done

이는 POSIX 쉘 명령 언어 기능 및 유틸리티만 사용합니다. 이 한 줄짜리 문장은 불필요한 세미콜론을 제거하고 들여쓰기를 사용하여 더 명확해졌습니다.

for x in *; do
  case "$x" in
    *.jpg|*.png|*.bmp) 
       ;; # nothing
    *) # catch-all case
       mv -- "$x" target
       ;;
  esac
done

관련 정보