답변:
xargs
작업을위한 도구입니다. 그것으로 또는 find
로 -exec … {} +
. 이러한 도구는 명령을 여러 번 실행하며 한 번에 전달할 수있는 많은 인수를 사용합니다.
변수 인수 목록이 끝날 때 두 방법 모두 수행하기가 더 쉽습니다. 여기에는 해당되지 않습니다. 최종 인수 mv
는 대상입니다. GNU 유틸리티 (즉, 내장되지 않은 Linux 또는 Cygwin) 에서 대상을 먼저 전달하는 -t
옵션 mv
이 유용합니다.
파일 이름에 공백이나가 없으면 \"'
파일 이름을 입력으로 제공 할 수 있습니다 xargs
( echo
명령은 bash 내장이므로 명령 행 길이 제한이 적용되지 않습니다).
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/
shopt -s extglob
활성화 할 수 있습니다. 나는 find
명령 에서 한 단계를 놓쳤다 . 나는 그들을 고쳤다.
find
내가 게시 한 명령이 작동합니다. 복사-붙여 넣기시 부품을 남겨 두어야합니다.
!
않습니까? 홀수 후행보다 더 명확하고 이해하기 쉽습니다 -o
. 예 :! -name '*.jpg' -a ! -name '*.png' -a ! -name '*.bmp'
리눅스 커널로 작업하는 것만으로 충분하다면 간단하게 할 수 있습니다
ulimit -s 100000
그것은 리눅스 커널이 약 10 년 전에 스택 크기에 따라 인수 제한을 변경 한 패치를 포함했기 때문에 작동합니다 : https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ commit /? id = b6a2fea39318e43fee84fa7b0b90d68bed92d2ba
업데이트 : 당신이 용감하다고 생각하면 말할 수 있습니다
ulimit -s unlimited
RAM이 충분하다면 쉘 확장에 문제가 없을 것입니다.
ulimit -s unlimited
사실상 무제한 파일에 대해 작동합니다.
ulimit -s unlimited
실제 명령 라인 한도 2 ^ 31 2GB입니다. ( MAX_ARG_STRLEN
커널 소스에서)
운영 체제의 인수 전달 한계는 쉘 인터프리터 내에서 발생하는 확장에는 적용되지 않습니다. 그래서 사용하는 것 외에도 xargs
또는 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
mv
한 POSIX find
솔루션을 사용하는 데 필요한 몇 가지 파일 대신 백만 개가 넘는 프로세스 가 생성 됩니다. 다시 말해, 이런 식으로 불필요한 CPU 이탈이 많이 발생합니다.
case
결과에 대한 설명 *
이 원래 !(*.jpg|*.png|*.bmp)
표현식 과 동일 하다는 것을 쉽게 알 수 있습니다 . 그 find
대답은 사실 동일하지 않습니다. 하위 디렉토리로 내려갑니다 (나는 -maxdepth
술어 가 보이지 않습니다 ).
-name . -o -type d -prune -o
하위 디렉토리로 내려 가지 않도록 보호합니다. -maxdepth
비록 내 find
매뉴얼 페이지 에서 언급되지 않았지만 POSIX와 호환되지 않습니다 .
이전에 제공된 것보다 더 공격적인 솔루션을 얻으려면 커널 소스를 가져 와서 편집하십시오. include/linux/binfmts.h
크기를 MAX_ARG_PAGES
32보다 큰 것으로 늘리십시오. 이렇게하면 커널이 프로그램 인수에 허용하는 메모리 양이 증가하여 백만 개의 파일 또는 수행중인 작업에 대해 명령 mv
또는 rm
명령 을 지정할 수 있습니다 . 재 컴파일, 설치, 재부팅
조심해! 이 값을 시스템 메모리에 너무 크게 설정 한 후 많은 인수를 사용하여 명령을 실행하면 잘못된 결과가 발생합니다! 다중 사용자 시스템에서는이 작업을 신중하게 수행해야합니다. 악의적 인 사용자가 모든 메모리를보다 쉽게 사용할 수 있습니다!
커널을 수동으로 다시 컴파일하고 다시 설치하는 방법을 모르는 경우 현재로서는이 답변이 존재하지 않는다고 가정하는 것이 가장 좋습니다.
"$origin"/!(*.jpg|*.png|*.bmp)
catch 블록 대신 사용하는보다 간단한 솔루션 :
for file in "$origin"/!(*.jpg|*.png|*.bmp); do mv -- "$file" "$destination" ; done
@Score_Under 덕분에
여러 줄 스크립트의 경우 다음을 수행 할 수 있습니다 (이를 삭제 ;
하기 전의 주의 사항 done
).
for file in "$origin"/!(*.jpg|*.png|*.bmp); do # don't copy types *.jpg|*.png|*.bmp
mv -- "$file" "$destination"
done
모든 파일을 이동시키는보다 일반적인 솔루션을 수행하려면 단일 라이너를 사용할 수 있습니다.
for file in "$origin"/*; do mv -- "$file" "$destination" ; done
들여 쓰기를하면 다음과 같이 보입니다.
for file in "$origin"/*; do
mv -- "$file" "$destination"
done
원본의 모든 파일을 가져 와서 대상으로 하나씩 이동합니다. $file
파일 이름에 공백이나 다른 특수 문자가있는 경우 따옴표 가 필요합니다.
다음은 완벽하게 작동 한이 방법의 예입니다.
for file in "/Users/william/Pictures/export_folder_111210/"*.jpg; do
mv -- "$file" "/Users/william/Desktop/southland/landingphotos/";
done
!(*.jpg|*.png|*.bmp)
. "$origin"/!(*.jpg|*.png|*.bmp)
Kaz의 답변에 사용 된 스위치가 필요하지 않고 for-loop의 간단한 몸체를 유지하는 globbing을 통해 for-loop에 추가 할 수 있습니다 .
여기 내 두 센트가 있습니다. .bash_profile
mv() {
if [[ -d $1 ]]; then #directory mv
/bin/mv $1 $2
elif [[ -f $1 ]]; then #file mv
/bin/mv $1 $2
else
for f in $1
do
source_path=$f
#echo $source_path
source_file=${source_path##*/}
#echo $source_file
destination_path=${2%/} #get rid of trailing forward slash
echo "Moving $f to $destination_path/$source_file"
/bin/mv $f $destination_path/$source_file
done
fi
}
export -f mv
용법
mv '*.jpg' ./destination/
mv '/path/*' ./destination/