更新:2014年12月10日 - 固定!! 脚本在文件夹+ all_subfolders中查找所有jpg,jpeg,JPG文件,并设置文件修改时间戳= exif日期/时间。 +它也将图像的大小写入文件名。 (通过查看filname来了解图像的像素大小)
原件: 我一直在编写一个脚本,拿起信息和信息的痕迹来使用。 我设法制作了一个剧本。在文件夹中运行它,它将获取当前和子文件夹中的所有.jpg .JPG并将它们重命名为filename。即: 2014_10_19_12_24_05_DSC-RX100_F5.6_f37.1mm_1T250s_ISO320.jpg
问题
照片可能是以快速快门速度同时拍摄的。例如:
2014_10_19_12_24_05_DSC-RX100_F5.6_f37.1mm_1T250s_ISO320.jpg(原文件名P00002727.jpg)
2014_10_19_12_24_05_DSC-RX100_F5.6_f37.1mm_1T250s_ISO320.jpg(原文件名P00002728.jpg)
第一个文件写得好,然后第二个文件覆盖第一个文件: - /
如果有人可以提供帮助
我希望脚本有一个" if文件存在,新文件名应该重命名为增加数字01,02,03..etc .."在文件名的末尾。像这样:
2014_10_19_12_24_05_DSC-RX100_F5.6_f37.1mm_1T250s_ISO320.jpg
2014_10_19_12_24_05_DSC-RX100_F5.6_f37.1mm_1T250s_ISO320_01.jpg(已添加_01,02,03等..)
我使用的脚本:
#!/bin/bash
#extensions="jpg,jpeg,png,gif,psd,bmp,crw,thm,tif,tiff"
fileTypes="jpg,jpeg,JPG"
#make regex to find files with extensions in $fileTypes
fileTypes=".*\.\(${fileTypes//,/\|}\)"
# loop through all the image files
find . -iregex "$fileTypes" -print0 | sort | while read -d "" s
#find . -iregex '.*\.\(jpg\|JPG\|jpeg\)$' -print0 | while read -d $'\0' s
#find . -name "*.jpg" -print0 | while read -d $'\0' s
#find . -type f -iname "*.jpg" -print0 | while read -r -d $'\0' s ;
#find . -iname "*.jpg" -print0 | while read -d $'\0' s ;
#for s in $(find . -iname *.jpg -print0 | while read -d $'\0' s);
do
echo "------------ Start --------------------------"
echo ""
let counting=counting+1
echo "Number of files: $counting"
## skip files that already contain _XX increment
#ffn="${s##*/}" # full filename w/o path
#fn="${ffn%.*}" # split filename from ext
#if [ "${fn: -3:1}" = '_' ]; then # have we added '_XX' before ?
# continue # skip to next file 's'
#fi
header=`jhead "$s"` # header holds jhead info about
justFileName=`basename "$s" | sed 's/\(.*\)\..*/\1/'`
dateTime=`echo "$header" | grep "Date/Time"` # dateTime fetches Date Time line
fileDate=`echo "$header" | grep "File date"`
path="`pwd "$s"/ `"
file="`echo "$s" | sed 's/^.//'`" # . = 1. first chars is removed in front
pathwithfile="`echo $path$file`" # does not lookup directory with spaces
pathwithspaces="$PWD$file" # does lookup direcotyr with spaces!
justPath=`dirname "$pathwithfile"`
exifdateTime=`echo $dateTime | awk -F ":" '{print $2"_"$3"_"$4"_"$5"_"$6}' | awk -F " " '{print $1"_"$2}'`
dateFileTime=`echo $fileDate | awk -F "_" '{print $1"_"$2"_"$3"_"$4"_"$5"_"$6}' | awk -F ":" '{print $2"_"$3"_"$4"_"$5"_"$6}'`
#| cut -c 16-34`
#datefileName=`echo $justFileName | cut -c 1-19`
FULLPATH="$pathwithspaces"
# remove all the prefix until "/" character
FILENAME=${FULLPATH##*/}
# remove all the prefix unitl "." character
FILEEXTENSION=${FILENAME##*.}
# remove a suffix, in our cas, the filename, this will return the name of the directory that contains this file
BASEDIRECTORY=${FULLPATH%$FILENAME}
#echo "FULLPATH = $FULLPATH"
#echo "FILENAME = $FILENAME"
#echo "FILEEXTENTION = $FILEEXTENSION"
#echo "BASEDIRECTORY = $BASEDIRECTORY"
#echo "dateTime: $dateTime"
#echo "exifdateTime: $exifdateTime"
#echo "fileDate: $fileDate"
#echo "dateFileTime: $dateFileTime"
#echo "pathwithfile: $pathwithfile"
#echo "pathwithspaces: $pathwithspaces"
stripedfilename=`echo $FILENAME | cut -c 1-19`
if [ $exifdateTime = $stripedfilename ]; then
echo "File \"$s\" already exists with exifdateTime: $stripedfilename"
echo "..skip to next file"
echo "--- End ---"
continue
stripedfiledate=$fileDate | cut -c 1-19
if [ $stripedfiledate = $stripedfilename ] ; then
echo "File \"$s\" already exists with fileDate: $stripedfiledate"
echo "..skip to next file"
echo "--- End ---"
continue
fi
fi
#echo "break"
#break
#if [ -z "$dateTime" ] || [[ $dateTime == "Date/Time : 0000:00:00 00:00:00" ]];
if [ "$dateTime" = "Date/Time : 0000:00:00 00:00:00" ]
then
if [ -z "$fileDate" ]
then
# If Date/Time=0000:00:00 check File date
dateTime=`echo "$header" | grep "File date"`
# echo "Date/Time(ny): $fileDate"
# Set timestamp from exif
# echo "File date(ny): $exifdateTime"
jheadrun=`jhead -autorot -exonly -ft -norot "$FULLPATH"`
else
# Set exif = modified timestamp.
jheadrun=`jhead -dsft "$FULLPATH"`
#echo "..fixed Date/Time: 0000..."
#echo "break 1"
#break
fi
# Set new dateTime
header=`jhead "$s"` # header holds jhead info about
dateTime=`echo "$header" | grep "Date/Time"`
#justFileName=`basename "$s" | sed 's/\(.*\)\..*/\1/'`
exifdateTime=`echo $dateTime | awk -F ":" '{print $2"_"$3"_"$4"_"$5"_"$6}' | awk -F " " '{print $1"_"$2}'`
fi
# if -z variable is zero
# if -n variable is none-zero
if [ "$fileDate" = "" ] ;
then
#echo "break 2"
#break
#echo "breake 2 - True"
# Set exif = modified timestamp.
jheadrun=`jhead -dsft "$FULLPATH"`
# echo "jhead -dsft $jheadrun"
else
#echo "break 2 - False"
# Set Date/Time from File-modification timestamp
# echo "Date/Time(ny): $exifdateTime"
jheadrun=`jhead -autorot -exonly -ft -norot "$FULLPATH"`
# echo "`jhead -autorot -exonly -ft -norot \"$FULLPATH\"`"
fi
#
# check file do have Modification date
# if yes
# set Date/Time = modification date
#
if [ "$dateTime" = "" ] ;
then
#echo "break 3"
#break
echo "breake 3 - True"
# Set exif = modified timestamp.
jheadrun=`jhead -mkexif -dsft "$FULLPATH"`
echo "jhead -mkexif -dsft $jheadrun"
fi
if [ "$exifdateTime" != "$dateFileTime" ]
then
#echo "break 4"
#break
# echo $s
x=`jhead "$s" | \
awk 'BEGIN { cmt=""; }
#/File name/ { n=$4; gsub(".jpg","",n);}
/Camera model/ { c=$4$5$6;}
/Exposure time:/ { e=$3;
if (e==int(e)) e=int(e);
if (e<1) {e=int(0.5+1/e); e="1T" e "s";} else { e=e "s"; }
}
/ISO equiv./ { iso="ISO" $4; }
/Focal length/ { f="f" $4; }
/Date.Time / { d=$3 "_" $4; gsub(":","_",d); }
/Resolution / { size=$3$4$5$6; }
/Aperture / { ap=$3; gsub("f/","F",ap); }
/Comment / { cmt=$3 "_"; }
END { print d "_" c "_" size "_" ap "_" f "_" e "_" iso ".jpg"; }'`
commentcheck=`echo "$header" | grep Comment | awk -F ":" '{print $2}'`
if [ "$commentcheck" != " Original_filename" ]
then
#echo "break 5"
comment="Original_filename: $FILENAME"
commentcommand="jhead -cl \"$comment\""
echo "..no comment in file, adding; $comment <-- adding comment"
#echo "commment: $comment"
#echo "commentcheck: $commentcheck <-- if this is blank file does not have comment"
#echo "commentcommand: $commentcommand"
addcomment="$commentcommand \"$pathwithfile\""
#addcomment=("jhead -cl $comment $pathwithfile")
#echo "addcomment: $addcomment"
eval $addcomment # Run variable in terminal
else
continue
fi
#echo "break 6"
#break
########
PADDING=2
NEWFILE="$BASEDIRECTORY$x"
if [[ -f $NEWFILE ]]; then
BASE=`echo $x | sed "s/\.jpg/_/"`
#echo $BASE
LAST=`ls -1 "$BASEDIRECTORY" | grep $BASE | sort -r | head -1`
#echo $LAST
LASTNUM=`echo ${LAST:${#x}-3:$PADDING} | sed "s/^0*//"`
#echo $LASTNUM
let LASTNUM=LASTNUM+1
#echo $LASTNUM
FINAL=$BASE$(printf "%0"$PADDING"d.jpg" ${LASTNUM})
#echo $FINAL
NEWFILE=$BASEDIRECTORY$FINAL
fi
mv "$s" "$NEWFILE"
#NODUPLICATE="jhead -n%f-%02i \"$pathwithspaces\" \"$NEWFILE\""
#echo "mv \"$pathwithspaces\" \"$NEWFILE\""
echo "New filename: $NEWFILE"
#echo "---"
#header=`jhead "$NEWFILE"`
#echo "$header"
#echo "---"
#echo "break 6"
#break
#echo "$s"
fi # END OF if [ "$exifdateTime" != "$datefileName" ]
unset x
#echo "$x"
#echo "Sleeping 1/100 of a second"
sleep 0.01
#sleep 0.05
#sleep 3
echo "End..------------------------------------------------"
echo ""
done
答案 0 :(得分:1)
在:
mv "$s" "$NEWFILE"
使用类似的东西:
PADDING=2
echo "New filename: "
NEWFILE="$BASEDIRECTORY$x"
if [[ -f $NEWFILE ]]; then
BASE=`echo $x | sed "s/\.jpg/_/"`
LAST=`ls -1 $BASEDIRECTORY | grep $BASE | sort -r | head -1`
LASTNUM=`echo ${LAST:${#x}-3:$PADDING} | sed "s/^0*//"`
let LASTNUM=LASTNUM+1
FINAL=$BASE$(printf "%0"$PADDING"d.jpg" ${LASTNUM})
NEWFILE=$BASEDIRECTORY$FINAL
fi
您当然可以使用脚本的counter
来处理序列号,但此版本在重新运行时不会重新计算(我认为更安全)。
答案 1 :(得分:1)
你创建NEWFILE="$BASEDIRECTORY$x"
的地方你需要这样的东西:
#!/bin/bash
echo "New filename: "
NEWFILE="$BASEDIRECTORY$x"
ntmp="$NEWFILE"
while [ -e "$ntmp" ]; do # while the file "$ntmp" exist...
ffn="${ntmp##*/}" # full filename w/o path
fn="${ffn%.*}" # split filename from ext
ext="${ntmp#*${fn}.}" # get the ext
if [ "${fn: -3:1}" = '_' ]; then # does filename have '_XX' ?
if [[ "${fn: -2}" =~ [^0-9] ]]; then # if 'XX' isn't 2 digits [0-9]
ntmp="${fn}_01.${ext}" # it's not ours, just add _01, and
continue # continue
fi
count=$((${fn: -2}+1)) # if 2-digits, get the XX and add +1
if [ "$count" -lt 10 ]; then
ntmp="${fn:0:$((${#fn}-3))}_0${count}.${ext}" # if 1-digit, replace w/ '_0${count}'
else
ntmp="${fn:0:$((${#fn}-3))}_${count}.${ext}" # if 2-digit, replace w/ '_${count}'
fi
else # if first dup, just add '_01'
ntmp="${fn}_01.${ext}"
fi
done
mv "$s" "$ntmp"
重复文件名:
$ ls -1 20*
2014_10_19_12_24_05_DSC-RX100_F5.6_f37.1mm_1T250s_ISO320.jpg
2014_10_19_12_24_05_DSC-RX100_F5.6_f37.1mm_1T250s_ISO320_01.jpg
2014_10_19_12_24_05_DSC-RX100_F5.6_f37.1mm_1T250s_ISO320_02.jpg
注意:使用反向字符串索引(例如${fn: -2}
)时,必须在{{1}之前加一个空格}符号(或将索引放在括号中(例如-
)。
在${fn:(-2)}
中工作时尝试利用bash提供的工具并远离使用外部应用程序和管道(每个应用程序和管道产生一个单独的进程和子shell),例如(bash
,{ {1}},grep
和&#39; |&#39;)。实际上,只要字符串/行解析利用其自己的参数扩展/子字符串提取/子字符串替换和字符串索引,bash就无法做任何事情。从脚本中调用外部应用程序没有任何问题,只是不要用它们来代替已经为你做的bash。
由于您使用的是awk
和cut
,因此您可能会对此Iphone Image Rename w/jhead脚本中的一些想法感兴趣。这需要稍微不同的方法来解析bash
图像输出,并且有一些方便的功能可以使用。
根据我们在评论中的讨论,如果您通过脚本提供所有文件名(包括先前以_XX增量递增的文件名),您将希望再次跳过处理这些文件。
要省略已从主循环递增的文件,您需要在jhead
循环的开头添加以下内容:
jhead
行。为了深入了解这一点,并帮助我们更有效地进行沟通,我创建了一个测试用例脚本。我遇到的问题是我没有你的相机或文件中的文件知道我正在处理的是什么。这使我试图尽可能广泛地处理所有情况(无论如何都应该这样做)。但以下内容将允许针对输出文件名测试输入文件。我已经保留了原始脚本内容(在注释中)以显示测试所在的上下文,并且我已经评论并替换了测试用例所需的部分。以下是经过验证的脚本和测试用例:
find | while
现有文件:
# loop through all the image files
find . -iregex "$fileTypes" -print0 | while read -d "" s
do
## skip files that already contain _XX increment
ffn="${s##*/}" # full filename w/o path
fn="${ffn%.*}" # split filename from ext
if [ "${fn: -3:1}" = '_' ]; then # does the file have '_XX' suffix
if [[ "${fn: -2}" =~ [0-9][0-9] ]]; then # if 2 digits, assume prior increment
continue # skip to next file 's'
fi
fi
文件重命名:
#!/bin/bash
# fileTypes="jpg,jpeg"
#make regex to find files with extensions in $fileTypes
# fileTypes=".*\.\(${fileTypes//,/\|}\)"
# loop through all the image files
# find . -iregex "$fileTypes" -print0 | while read -d "" s
for s in "$@"
do
## skip files that already contain _XX increment
ffn="${s##*/}" # full filename w/o path
fn="${ffn%.*}" # split filename from ext
if [ "${fn: -3:1}" = '_' ]; then # does the file have '_XX' suffix
if [[ "${fn: -2}" =~ [0-9][0-9] ]]; then # if 2 digits, assume prior increment
continue # skip to next file 's'
echo "XX is digits, skipping"
fi
fi
## rest of your script here...
#NEWFILE="$BASEDIRECTORY$x"
NEWFILE="$s"
ntmp="$NEWFILE"
while [ -e "$ntmp" ]; do # while the file "$ntmp" exist...
ffn="${ntmp##*/}" # full filename w/o path
fn="${ffn%.*}" # split filename from ext
ext="${ntmp#*${fn}.}" # get the ext
if [ "${fn: -3:1}" = '_' ]; then # does filename have '_XX' ?
if [[ "${fn: -2}" =~ [^0-9] ]]; then # if 'XX' isn't 2 digits [0-9]
ntmp="${fn}_01.${ext}" # it's not ours, just add _01, and
continue # continue
fi
count=$((${fn: -2}+1)) # if 2-digits, get the XX and add +1
if [ "$count" -lt 10 ]; then
ntmp="${fn:0:$((${#fn}-3))}_0${count}.${ext}" # if 1-digit, replace w/ '_0${count}'
else
ntmp="${fn:0:$((${#fn}-3))}_${count}.${ext}" # if 2-digit, replace w/ '_${count}'
fi
else # if first dup, just add '_01'
ntmp="${fn}_01.${ext}"
fi
done
# mv "$s" "$ntmp"
if [ "$s" = "$ntmp" ]; then
printf "\n no change : %s\n\n" "$s"
else
printf "\n file exists : %s\n new fname : %s\n\n" "$s" "$ntmp"
fi
done
exit 0
答案 2 :(得分:0)
man mv(1)
包含您需要的所有信息。这是使用数字备份选项
% touch aaa1 aaa2 aaa3 aaa4
% for fn in {1..4} ; do mv --backup=t aaa$fn bbb1 ; done
% ls bbb*
bbb1 bbb1.~1~ bbb1.~2~ bbb1.~3~
%
使用mv --backup=t ...
有一个小缺陷,它使用上一个移动文件的普通名称,在我上面的示例中aaa1 -> bbb1.~1~
,aaa2 -> bbb1.~2~
,aaa3 -> bbb1.~3~
和(但) aaa4 -> bbb1
。
这与mv
POV完全合乎逻辑,可能不太适合OP。
下面的脚本将未编号的文件移动到其逻辑位置 (适用于需要在当天结束时重命名的任意数量的文件)
% for x in $(sed s/....\$// <(printf %s\\n *.\~?\~) | uniq) ; do
> if [ -f $x ] ; then
> last=$(ls ${x}*~ |tail -1 | sed -r 's/(.*)~([0-9]+)~$/\2/')
> mv $x $x.'~'$(($last+1))'~'
fi
> done
% ls bbb1*
bbb1.~1~ bbb1.~2~ bbb1.~3~ bbb1.~4~
%
以非常短的顺序拍摄的照片现在都编号为1到N