파일 확장자를 기준으로 파일 정렬

파일 확장자를 기준으로 파일 정렬

확장자에 따라 파일을 정렬하고 올바른 폴더에 배치하는 스크립트를 만들었습니다. 예를 들어, abc.jpg디렉토리에 배치됩니다 jpg.

#!/bin/bash
#this script sorts files according to their extensions
oldIFS=$IFS
IFS=$'\n'
(find . -type f) > /tmp/temp
for var in `cat /tmp/temp`
do
name=`basename "$var"`
ext=`echo $name | cut -d'.' -f2- | cut -d'.' -f2- | cut -d'.' -f2- | cut -d'.' -f2- | cut -d'.' -f2- | cut -d'.' -f2- | cut -d'.' -f2-`
mkdir -p $ext
mv "$var" $ext/ 2> /dev/null
done
IFS=$oldIFS

이 스크립트의 문제점:

  1. IFS 사용에 관해서는 IFS 사용을 피하도록 노력해야 한다고 합니다.
  2. 파일 확장자가 없는 파일은 정렬되지 않습니다.
  3. bz라는 폴더에 abc.tar.bz와 같은 파일을 정렬하지만 이러한 파일은 tar.bz 폴더에 배치해야 합니다.
  4. 파일에 더 많은 숫자가 포함되어 있으면 내 스크립트의 9행을 참조하세요. 아무것도 아닌 것보다 (그 이름에) 포인트를 줍니다. cut -d'.' -f2-스크립트에서 파일 이름이 확장 부분에 포함됩니다.
    예를 들어, 이름이 지정된 파일은 i.am.live.in.india.and.i.study.computer.science.txt이름이 지정된 폴더에 배치됩니다.study.computer.science.txt

또한 이 스크립트를 더 작고 깔끔하게 만들기 위해 조정을 제안할 수도 있습니다.

답변1

하위 디렉터리로 재귀

구문 분석된 출력을 find신뢰할 수 없습니다. 파일 이름에 줄 바꿈이 있으면 어떻게 되나요? find … -exec …안정적인 처리를 보장하는 데 사용됩니다 .

find . -type f -exec sh -c '…' {} \;

셸 조각은 을 받습니다 $0. 이는 별도의 셸 프로세스이며 상위 스크립트에서 변수나 함수를 상속하지 않습니다. 동일한 셸 하위 프로세스를 사용하여 여러 파일을 처리하면 처리 속도를 높일 수 있습니다.

find . -type f -exec sh -c 'for x; do … done' _ {} +

이번에는 루프 내부에서 파일 이름이 변수에 있습니다 x.

파일 이름 분해

외부 유틸리티(예: 등)를 호출하는 것은 sed취약 cut합니다. 특정 파일 이름이 손상되지 않도록 매우 주의해야 합니다. 이것은 필요하지 않습니다. 쉘의 내장 문자열 처리 기능만으로도 원하는 작업을 수행할 수 있습니다. 파일 이름이 주어지면 $x:

directory=${x%/*}
basename=${x##*/}
extension=…
if [ -n "$extension" ]; then
  mkdir -p "$directory/extension"
  mv "$x" "$directory/extension"
fi

확장하다

파일 확장자는 무엇입니까? .이름 중 하나 뒤에 오는 부분 입니다 . 어느 쪽인지에 대한 표준은 없습니다. 또는 같은 경우 에는 foo.tar.gz확장자가 무엇인지 결정합니다 bar-1.2.

foo-1.2.tar.gz다음은 일반적인 압축 확장이 중첩된 것으로 간주하고 확장이 있는 것으로 간주되도록 확장에 문자를 포함하도록 요구하는 몇 가지 예제 코드입니다 tar.gz.

extension=
while case "${basename##*.}" in
        gz|bz2|xz) extension=.${basename##*.}$extension;; # stackable extension
        *) false;;
do
  basename=${basename%.*}
done
case "${basename##*.}" in
  "$basename") :;; # no . ==> no extension
  *[!0-9A-Za-z]*) :;; # only allow alphanumeric characters
  *[A-Za-z]*) extension=${basename##*.}$extension;; # non-stackable extension
  *) false;; # require at least one letter
esac
extension=${extension#.}

답변2

확장 기능의 일반적인 문제를 식별하는 것은 어렵지만 스크립트를 약간 정리할 수 있습니다.

  1. find확장자가 있는 파일만 고려하도록 지시 합니다.-iname '*.*'
  2. awk직접 시도하는 대신 다음을 사용하십시오 cut.
  3. 스크립트를 사용한 다음 find실행하도록 지시하십시오.

따라서 다음과 같은 스크립트가 필요합니다 move.sh.

#! /bin/bash
for i
do
    ext=/some/where/else/$(awk -F. '{print $NF}' <<<"$i")
    mkdir -p "$ext"
    mv "$i" "$ext"
done

그런 다음 다음을 실행하십시오 find.

find . -name '*.*' -type f -exec move.sh {} +

폴더 내에서 재정렬할 수 없다는 문제가 있으므로 다음을 사용할 수 있습니다 xargs.

find . -name '*.*' -type f -print0 > /tmp/temp
xargs -0 move.sh < /tmp/tmp

관련된 효율성에 대해서는 잘 모르겠지만 다른 접근 방식은 모든 확장자를 가져온 다음 관련된 모든 파일을 한 번에 이동하는 것입니다.

그것은 다음과 같습니다:

find . -name '*.*' -type f -print0 | sed -z 's/.*\.//g' | sort -zu > /tmp/file-exts

그러면 고유한 파일 확장자 목록이 제공됩니다. 그러면 우리는 move.sh다음과 같이 보일 것입니다 :

#!/bin/bash
for i
do
    mkdir -p "$i"
    find . -name "*.$i" -type f -exec mv -t "$i" {} +
done

우리는 그것을 실행할 것입니다:

xargs -0 move.sh < /tmp/file-exts

sed나는 이 게시물에서 예 를 들어 sort지원 ( -zNUL 종료 라인으로 작업 find하고 xargs성공할 수 있도록 허용) 과 같은 많은 가정을 했습니다 .

관련 정보