내 다운로드 폴더를 탐색하고 확장자에 따라 파일을 정렬하는 작은 스크립트가 있습니다.
내가 이걸 어떻게 할 수 있지?더 깨끗하고/더 좋음? 확장명을 추가할 때마다 새 줄을 추가할 필요가 없도록 확장명과 해당 디렉터리 목록을 유지하고 for 루프 등을 사용하여 명령을 실행하고 싶습니다.
현재 스크립트:
#!/bin/sh
LOCKFILE=/tmp/.hiddensync.lock
if [ -e $LOCKFILE ]
then
echo "Lockfile exists, process currently running."
echo "If no processes exist, remove $LOCKFILE to clear."
echo "Exiting..."
exit
fi
touch $LOCKFILE
timestamp=`date +%Y-%m-%d::%H:%M:%s`
echo "Process started at: $timestamp" >> $LOCKFILE
## Move files to various subfolders based on extensions
find ~/Downloads -maxdepth 1 -name "*.pdf" -print0 | xargs -0 -I % mv % ~/Downloads/PDF/
find ~/Downloads -maxdepth 1 -name "*.opm" -print0 | xargs -0 -I % mv % ~/Downloads/OPM/
find ~/Downloads -maxdepth 1 -name "*.yml" -print0 | xargs -0 -I % mv % ~/Downloads/YML/
find ~/Downloads -maxdepth 1 -name "*.css" -print0 | xargs -0 -I % mv % ~/Downloads/CSS/
find ~/Downloads -maxdepth 1 -name "*.tar.gz" -print0 | xargs -0 -I % mv % ~/Downloads/archives/
find ~/Downloads -maxdepth 1 -name "*.zip" -print0 | xargs -0 -I % mv % ~/Downloads/archives/
find ~/Downloads -maxdepth 1 -name "*.jpg" -print0 | xargs -0 -I % mv % ~/Downloads/Pictures/
find ~/Downloads -maxdepth 1 -name "*.png" -print0 | xargs -0 -I % mv % ~/Downloads/Pictures/
find ~/Downloads -maxdepth 1 -name "*.tiff" -print0 | xargs -0 -I % mv % ~/Downloads/Pictures/
find ~/Downloads -maxdepth 1 -name "*.pm" -print0 | xargs -0 -I % mv % ~/Downloads/Perl/
find ~/Downloads -maxdepth 1 -name "*.xls*" -print0 | xargs -0 -I % mv % ~/Downloads/Excel/
find ~/Downloads -maxdepth 1 -name "*.doc*" -print0 | xargs -0 -I % mv % ~/Downloads/Word/
echo "Task Finished, removing lock file now at `date +%Y-%m-%d::%H:%M:%s`"
rm $LOCKFILE
답변1
대상에 여러 확장이 있는 경우 find
지시문에 더 많은 논리를 추가할 수 있습니다.
find ~/Downloads -maxdepth 1 \( -name "*.tar.gz" -o -name "*.zip" \) -print0 | xargs -0 -I % mv % ~/Downloads/archives/
그리고 xargs로 파이프할 필요가 없습니다.
find ~/Downloads -maxdepth 1 \( -name "*.tar.gz" -o -name "*.zip" \) -exec mv -t ~/Downloads/archives/ {} +
이제 그것을 가지게 되었는데 -maxdepth 1
, 정말로 그것이 필요합니까 find
?
shopt -s nullglob
cd ~/Downloads
mv -t archives/ *.tar.gz *.zip
mv -t Pictures/ *.jpg *.png *.tiff
# etc
이 방법을 사용하면 이동할 파일이 없으면 일부 오류가 발생합니다. 다음과 같이 이 문제를 해결할 수 있습니다.
shopt -s nullglob
movefiles() {
local dest=$1
shift
if (( $# > 0 )); then
mkdir -p "$dest"
mv -t "$dest" "$@"
fi
}
cd ~/Downloads
movefiles PDF/ *.pdf
movefiles OPM/ *.opm
movefiles YML/ *.yml
movefiles CSS/ *.css
movefiles archives/ *.zip *.tar.gz
movefiles Pictures/ *.jpg *.png *.tiff
movefiles Perl/ *.pm
movefiles Excel/ *.xls*
movefiles Word/ *.doc*
노트:
- nullglob이 없으면 패턴과 일치하는 파일이 없으면 함수는 패턴을 문자열로 수신합니다.
- 예를 들어 pdf 파일이 없으면 쉘이 실행됩니다.
movefiles PDF/ "*.pdf"
- 예를 들어 pdf 파일이 없으면 쉘이 실행됩니다.
- nullglob의 경우 일치하는 항목이 없으면 쉘은 명령에서 패턴을 제거합니다.
movefiles PDF/
- 이것이 바로 인수 수를 확인하는 이유입니다. 일치하는 파일이 없으면 $#는 시프트 후 0이므로 아무것도 이동할 수 없습니다.
답변2
취향의 문제로, 나는 코드 복제를 싫어하고 데이터를 코드와 별도로 유지하는 경향이 있으므로 확장<->대상 관계를 정의하는 방법이 있습니다(여기서는 키 인덱스 배열에 있지만 구성 파일일 수도 있고 구성 파일일 수도 있음). sqlite 데이터베이스):
#! /bin/bash
declare -A destinations
destinations["jpg"]="images"
destinations["mp4"]="videos"
destinations["mov"]="videos"
shopt -s nullglob
for ext in "${!destinations[@]}"
do
files=(*.$ext)
[[ 0 -eq ${#files[*]} ]] && continue
mv -t ${destinations[$ext]} "${files[@]}"
done
이것은 목적을 위한 것입니다 bash
. 스크립트의 shebang은 sh
때때로 그것을 사용하고 bash
때로는 다른 것을 사용합니다( Ubuntu에서는...). 따라서 코드가 완전히 사소하지 않은 한 shebang에서는 사용 dash
하지 않을 것입니다 .sh
답변3
find
mv 명령은 단독으로 실행될 수 있습니다. 사용되는 구문은 다음과 같습니다.find <filter> -exec mv {} <destination>
참고:
{}
파일 이름으로 대체됩니다. 때로는 이 방법으로 이스케이프해야 할 수도 있습니다.\{\}
bash'isms를 허용한다면 bash 배열을 활용하고 다음과 같이 스크립트를 다시 작성할 수 있습니다.
BASE_PATH="~/Downloads/"
# 1st element: find filter, 2d element: destination
EXT_TO_PATH=(
'a=( "-iname \"*.pdf\" " "PDF" )'
'a=( "-iname \"*.jpg\" -o -iname \"*.png\" " "Pictures" )'
)
for elt in "${EXT_TO_PATH[@]}" ; do
eval $elt
echo "Extensions: ${a[0]}"
echo "Destination: ${a[1]}"
find $BASE_PATH -maxdepth=1 ${a[0]} -exec mv {} ${BASE_PATH}/${a[1]}
done
답변4
디렉터리를 따라 이동하고 일치하는 모든 항목을 차례로 각 디렉터리로 이동합니다.
for item in *
do
[[ -d "$item" ]] && mv -f *."$item" "$item" 2>/dev/null
done
의 오류 출력은 mv
삭제되므로 존재하지 않는 파일을 이동하려는 근거 없는 시도는 보고되지 않습니다.
또는 각 파일을 시도하고 해당 디렉터리로 이동할 수 있습니다.
for item in *
do
if [[ -f "$item" ]]
then
ext="${item##*.}"
[[ -d "$ext" ]] && mv -f "$item" "$ext"
fi
done