我有我已經在過去使用到m幾個Bash腳本將手工製作的文件存儲庫遷移到散列存儲庫,以便通過Web應用程序(主要是PHP應用程序)進行訪問和管理。在這些存儲庫中,文件名被散列(以避免與具有相同內容/名稱的文件發生衝突)並且文件均勻分佈(以確定性方式或隨機分佈)以保持每個文件的文件數量低於性能原因。以下是一個完整的示例:
#!/bin/bash
MAXFILESPERDIR=500
TARGETROOTDIR="./newrepository"
RANDOMDISTRIBUTION=1
if [ -d "$1" ]; then
LOGFILE=$(basename $0).$(date +"_%Y%m%d_%H%M").${$}.log
SQLFILE=$(basename $0).$(date +"_%Y%m%d_%H%M").${$}.sql
SOURCEDIR="$1"
TOTALSOURCEFILES=$(find "$1" -type f | wc -l)
let "TOTALTARGETDIRS=$TOTALSOURCEFILES/$MAXFILESPERDIR"
PADLENTARGETDIRS=${#TOTALTARGETDIRS}
PADLENTARGETFILE=${#TOTALSOURCEFILES}
echo "We will create $TOTALTARGETDIRS directories to hold $MAXFILESPERDIR files per directory."
if [ "$RANDOMDISTRIBUTION" == "1" ] ; then
echo "We will rename and distribute each file randomly."
else
echo "We will rename and distribute each file uniformly."
fi
echo "Do you want to continue?"
select choice in yes no ; do
if [ "$choice" == "yes" ] ; then
COUNTER=1
find "$1" -type f | while read SOURCEFILE ; do {
CHECKSUMFILE=$(sha1sum "$SOURCEFILE" | cut -d " " -f 1)
CHECKSUMNAME=$(echo "$SOURCEFILE" | sha1sum | cut -d " " -f 1)
DETERMINISTICNONCE=$(printf "%0${PADLENTARGETFILE}d\n" $COUNTER)
if [ "$RANDOMDISTRIBUTION" == "1" ] ; then
PROBABILISTICNONCE=$(let "XX=$RANDOM % $TOTALTARGETDIRS + 1" ; printf "%0${PADLENTARGETDIRS}d\n" $XX;)
else
PROBABILISTICNONCE=$(let "XX=$COUNTER % $TOTALTARGETDIRS + 1" ; printf "%0${PADLENTARGETDIRS}d\n" $XX;)
fi
FILEDATE=$(stat -c %z "$SOURCEFILE" | cut -d "." -f 1)
FILESIZE=$(stat -c %s "$SOURCEFILE")
echo "Source file $SOURCEFILE" >> $LOGFILE
echo "Target file $TARGETROOTDIR/$PROBABILISTICNONCE/$PROBABILISTICNONCE$CHECKSUMFILE$DETERMINISTICNONCE" >> $LOGFILE
echo "INSERT INTO files (Filename, Location, Checksum, CDate, Size) VALUES ('$PROBABILISTICNONCE$CHECKSUMFILE$DETERMINISTICNONCE', '$PROBABILISTICNONCE', '$CHECKSUMFILE', '$FILEDATE', $FILESIZE);" >> $SQLFILE
mkdir -p $TARGETROOTDIR/$PROBABILISTICNONCE
cp -v "$SOURCEFILE" $TARGETROOTDIR/$PROBABILISTICNONCE/$PROBABILISTICNONCE$CHECKSUMFILE$DETERMINISTICNONCE
let "COUNTER+=1"
} ; done
echo "Done."
echo
break
fi
if [ "$choice" == "no" ] ; then
echo
echo "Operation cancelled"
echo
break
fi
done
else
echo
echo "Missing source directory"
echo
fi
只需從新存儲庫的根目錄運行它。你可以配置它修改第一個變量:MAXFILESPERDIR定義每個目錄需要存儲多少個文件,TARGETROOTDIR是創建第一級目錄的第一級目錄的名稱(它只使用兩個級別,第一個是真正的單一目錄根),RANDOMDISTRIBUTION定義文件是否隨機分佈(它可能看起來不均勻,特別是對於小批量運行)或確定性(只是計數)。
它是如何工作(僅供參考,以防萬一這是不是你在找什麼,但也許你可以得到一些想法):
- 計數的源文件。
- 計算將創建多少個目標目錄。
- 請求確認。
- 對於每個文件:
- 計算文件內容的SHA1哈希值。
- 創建確定性隨機數。
- 創建概率隨機數(如果RANDOMDISTRIBUTION爲1,否則只是一個計數器)。
- 獲取大小和修改日期。
- 將隨機值的值與散列和計數器組合以獲得新文件名(路徑將是隨機值)。
- 記錄源和目標完整路徑。
- 創建並記錄SQL插入查詢。
- 創建目標目錄(如果它不存在)。
- 複製文件。 (你可以移動它,如果你想,但我玩的很安全)。
- 完成
如果設置RANDOMDISTRIBUTION爲1並運行該腳本幾次,你會得到你的源文件的副本,因爲每個文件將每次運行得到不同的目標文件名/路徑它。如果將RANDOMDISTRIBUTION設置爲其他內容,則每次運行腳本時,文件都將以相同的方式重命名(對於相同的文件集,如果添加或刪除文件,它們將得到不同的名稱/路徑)。
使用隨機值+散列+計數器的目的是確保我們可以處理重複(不會因計數器而發生碰撞),同時仍然隨機分發文件(對於足夠長的運行,這將分配文件均勻)。
此外,生成文件名的前綴也是該目錄的名稱,以便如果您有文件名和目錄名稱長度,則可以計算目錄名稱(以防萬一您不存儲在你的數據庫表中)。
最後,這是一次性遷移腳本,它並沒有真正寫入通過同一組文件定期執行。