이 명령을 사용할 때 mv * ..
오류가 발생합니다 -bash: /usr/bin/mv: Argument list too long
. 나는 이것이 발생하는 이유를 이해합니다. bash가 실제로 일치하는 모든 파일에 별표를 확장하여 매우 긴 명령줄을 생성하기 때문입니다. 이 오류를 어떻게 해결할 수 있나요?
답변1
제한은 bash가 아니라 execve()
외부 명령을 실행하는 데 사용되는 시스템 호출에 있습니다. 당신은 할 수 있습니다 :
printf '%s\0' * | xargs -r0 mv -t .. --
printf
에 내장되어 있으므로 그 시점에는 bash
없습니다 . 그리고 그 한계를 피하기 위해 인수 목록을 분할하는 것이 작업 execve()
입니다 . xargs
여기서는 -t
GNU의 GNU 특정 옵션을 사용합니다 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()
계산은 단지 거기에 있는 바이트의 합계가 아니며 수행 방법은 OS와 버전에 따라 다릅니다.
답변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
a가 있으면find
-mindepth
-maxdepth
find . -mindepth 1 -maxdepth 1 -exec sh -c 'mv -- "$@" ..' sh {} +
이러한 변형 중 어느 것도 이름 충돌을 고려하지 않습니다. 올바르게 백업된 데이터를 테스트해야 합니다.