我在这个目录中有大约 100 万个文件:/home/username/images/
每个文件的名称类似于:012345678910(Place)_0_20120414185957_28841.jpg
文件名的时间戳部分在每张图片上都发生变化。
下面的代码包含将文件排序/移动到此日期结构中的代码:/home/username/sorted/2012/04/14/18/name_of_file.jpg
对于小文件样本,它工作正常,但对于巨大的目录,我的腻子终端在输出后会断开连接
Directory $newdir does not exist. Creating same.
我有其他代码总是因错误代码而死亡argument list too long
。
这是代码:
#!/bin/bash
ALLFILES=(images/*)
for ((i=0; i<${#ALLFILES[*]}; i+=30000));
do
set $(echo "${ALLFILES[@]:i:30000}" | awk -F_ '{print $1, $2, $3, $4, $5}')
fullyear=$3
year=$(echo $fullyear |cut -c1-4)
month=$(echo $fullyear |cut -c5-6)
day=$(echo $fullyear |cut -c7-8)
hour=$(echo $fullyear |cut -c9-10)
newdir=$(echo /home/username/sorted/$year/$month/$day/$hour/)
if ! [ -d $newdir ]; then
echo Directory $newdir does not exist. Creating same.
mkdir -p $newdir;
fi
mv "${ALLFILES[@]:i:30000}" $newdir;
done
有什么想法为什么在执行大循环时连接无法保持?
答案1
尝试在屏幕会话中运行它。或者甚至尝试另一种结构。我相信 find + sed 会比纯 bash 工作得更好:
find images/ -name "*.jpg" | sed 's%^[^_]*_[^_]*_\([0-9][0-9][0-9][0-9]\)\([0-9][0-9]\)\([0-9][0-9]\)\([0-9][0-9]\).*%mkdir -p "/home/username/sorted/\1/\2/\3/\4" \&\& mv "&" "/home/username/sorted/\1/\2/\3/\4/"%'
这只是为了展示 sed make 命令如何执行。e
在最后添加后将%
强制执行命令:
find images/ -name "*.jpg" | sed 's%^[^_]*_[^_]*_\([0-9][0-9][0-9][0-9]\)\([0-9][0-9]\)\([0-9][0-9]\)\([0-9][0-9]\).*%mkdir -p "/home/username/sorted/\1/\2/\3/\4" \&\& mv "&" "/home/username/sorted/\1/\2/\3/\4/"%e'
附注你不需要在 bash 中使用
day=$(echo $fullyear |cut -c7-8)
Bash 可以自行完成,无需echo | cut
:
day=${fullyear:6:2}
答案2
我在包含文件的目录的根目录中使用这个 shell 脚本,将它们全部移动到year/month
类似的结构中:
#!/usr/bin/env bash
if [ ! $1 ]; then
echo "Usage: ./pictures.sh jpg"
exit 1
fi
for f in *."$1"; do
FILENAME="$f"
YEAR=`date -j -f "%s" $(stat -f "%m" "$FILENAME") +"%Y"`
MONTH=`date -j -f "%s" $(stat -f "%m" "$FILENAME") +"%m_%B"`
DEST="$YEAR/$MONTH"
if [ ! -d "$DEST" ]; then
mkdir -p "$DEST"
fi
echo "Moving $FILENAME to $DEST/$FILENAME ..."
mv "$FILENAME" "$DEST/$FILENAME"
done
用途:$ ./pictures.sh JPG
将 *.JPG 移动到正确的结构。
答案3
我还将图像分类到日期结构目录中,但我的方法略有不同。我希望我的图像YYYY-MM
根据时间戳进入各自的目录。所以我所做的就是从ls -l *.jpg > tmp.txt
图像文件夹开始,然后将其tmp.txt
输入循环以获取每个文件的时间戳。我还没有找到一种方法来获取时间戳。
这是我的代码:
#!/bin/bash
hostdir="/home/Photos/"
destdir="/tmp/sorted"
cd $hostdir
touch /tmp/tmpsort.txt
ls -l *.jpg > /tmp/tmpsort.txt
while read line
do
filename=$(echo $line | awk '{print $8}')
filedate=$(echo $line | awk '{print $6}')
filedir=${filedate:0:7}
if [ ! -d $destdir/$filedir ]; then
mkdir -p $destdir/$filedir
fi
# Let's skip files that were already sorted from a previous run
if [ ! -f $destdir/$filedir/$fiename ]; then
cp $filename $destdir/$filedir/
fi
done < /tmp/tmpsort.txt
rm /tmp/tmpsort.txt
我没有数百万张图像需要排序,如果有的话,这段代码将需要相当长的时间来执行。但它按预期工作。
答案4
以下一行将创建一个 shell 脚本,根据修改时间将文件移动到正确的文件夹。
find . -type f -not -name ".DS*" -exec stat -f "mkdir -p %Sm; mv \"%N\" %Sm" -t "%Y/%m/%d" {} \; > move.sh
sh move.sh
我已排除 .DS* 文件(-not -name ".DS*") 在执行 move.sh 之前,您可以对其进行编辑以删除不需要的文件。