"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대상을 먼저 전달하는 데 유용합니다.

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

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

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

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또는 let 및 다른 이름이 외부 명령을 계속 참조 하려는 경우 :

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

또는 ksh 스타일 glob을 사용하세요.

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입니다. 명령줄이 다음을 초과하는 경우저것, 문제를 직접 해결할 수 있기를 바랍니다.

as를 즉시 사용하면 sudo실제 실행 전에 스택 크기가 재설정되므로 문제를 해결할 수 없습니다. 이 문제를 해결하려면 를 사용하여 루트 셸을 시작한 다음 실행하고 마지막으로 루트 셸에서 명령을 실행하지 않고 명령을 실행해야 합니다.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

관련 정보