ファイル拡張子に基づいてファイルを並べ替える

ファイル拡張子に基づいてファイルを並べ替える

拡張子に従ってファイルをソートし、正しいフォルダに配置するスクリプトを作成しました。たとえば、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

拡大する

ファイル拡張子とは何ですか?.名前の1つの後の部分です。どちらにも標準はありません。または同じ場合は、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終了ラインで作業しfindxargs成功することを許可する)などの多くの仮定をしました。

関連情報