이 명령을 사용하면 mv * ..
오류가 발생합니다 -bash: /usr/bin/mv: Argument list too long
. 나는 이것이 일어나는 이유가 bash가 실제로 일치하는 각 파일에 별표를 확장하여 매우 긴 명령줄을 생성하기 때문이라는 것을 알고 있습니다. 이 오류를 어떻게 해결할 수 있나요?
답변1
제한은 bash에 있는 것이 아니라 execve()
외부 명령을 실행하는 데 사용되는 시스템 호출에 있습니다. 다음을 수행할 수 있습니다.
printf '%s\0' * | xargs -r0 mv -t .. --
printf
내장되어 있으므로 현재 bash
는 없습니다. 이 제한을 피하려면 매개변수 목록을 분할 execve()
해야 합니다 . GNU 의 GNU 특정 옵션이 xargs
여기에서 사용됩니다 .-t
mv
를 사용하면 내장된 항목을 zsh
로드할 수 있습니다 .mv
zmodload zsh/files
mv -- * ..
또는 zargs
도우미를 사용하여 분할을 수행합니다.
autoload -Uz zargs # best in ~/.zshrc
zargs -r -- ./* -- mv -t ..
with를 대체 ./*
하여 ./*(D)
숨겨진 파일을 이동하거나, oN
glob 한정자를 추가하여 파일 이름 정렬을 건너뛰거나, N
glob 한정자(with zargs -r
)를 추가하여 일치하는 파일이 없는 경우 오류를 방지할 수 있습니다.
zargs -r -- ./*(ND) -- mv -t ..
그것은 다음과 같습니다:
print -rNC1 ./*(ND) | xargs -r0 mv -t ..
그러나 GNU에 의존하지 않습니다 xargs
.
Linux(Ubuntu에서 일반적으로 사용되는 커널)에서는 리소스 제한을 execve()
늘려서 늘릴 수도 있습니다.stacksize
bash-5.1$ /bin/true {1..200000}
bash: /bin/true: Argument list too long
bash-5.1$ ulimit -s unlimited
bash-5.1$ /bin/true {1..200000}
bash-5.1$
완전히 제한되지는 않습니다(적어도 현재 버전의 커널에서는 아님).
bash-5.1$ /bin/true {1..2000000}
bash: /bin/true: Argument list too long
제한은 전달된 인수 및 환경 변수의 누적 크기이지만 execve()
계산은 단순히 바이트 합계 이상이며 수행 방법은 운영 체제 및 버전에 따라 다릅니다.
답변2
이 작업은 두 개 이상의 단계로 수행할 수 있습니다.
mv [a-k]* .. # or some other pattern matching a subset of the files
mv -- * ..
또는 루프에서
for name in *; do
mv -- "$name" ..
done
(그러나 이렇게 하려면 각 이름을 별도로 나열해야 합니다 mv
.)
또는 find
당신을 돕기 위해:
find . -mindepth 1 -maxdepth 1 -exec mv -t .. -- {} +
그러면 현재 디렉토리에서 모든 이름을 찾아 GNU를 사용하여 mv
가능한 적은 호출로 위의 디렉토리로 이동합니다 mv
.
GNU는 없지만 mv
여전히 find
비표준 -mindepth
및 -maxdepth
조건자를 인식하고 있습니다.
find . -mindepth 1 -maxdepth 1 -exec sh -c 'mv -- "$@" ..' sh {} +
이러한 변형 중 어느 것도 이름 충돌에 관심이 없습니다. 제대로 백업된 데이터로 테스트해야 합니다.