Bash

根據副檔名對文件進行排序

  • November 23, 2014

我製作了一個腳本,它將根據文件的副檔名對文件進行排序並將它們放在正確的文件夾中。例如,放置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 行;如果任何文件包含更多沒有。點數(以其名稱)比沒有。腳本中的ofcut -d'.' -f2-比 if 將導致在擴展部分中採用文件名。
    例如,一個名為的文件i.am.live.in.india.and.i.study.computer.science.txt將被放置在名為的文件夾中study.computer.science.txt

您還可以建議任何調整以使此腳本更小更整潔。

雖然辨識擴展的一般問題很難,但您可以稍微清理一下腳本:

  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

我在這篇文章中做了很多假設,例如sedsort支持-z(允許他們使用 NUL 終止的行findxargs茁壯成長)。

遞歸到子目錄

解析的輸出find是不可靠的。如果文件名中有換行符怎麼辦?使用find … -exec …,這保證了可靠的處理。

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

shell 片段接收$0. 請注意,這是一個單獨的 shell 程序,它不會從祖父腳本繼承變數或函式。您可以通過使用相同的 shell 子程序來處理多個文件來加快處理速度。

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

這一次,在循環內部,文件名在變數x.

拆分文件名

呼叫諸如 , 等外部實用程序sedcut脆弱的:您必須非常小心,以免破壞某些文件名。您不需要:shell 的內置字元串處理功能足以滿足您在此處執行的操作。給定一個文件名$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#.}

引用自:https://unix.stackexchange.com/questions/169594