Update: 10.12.2014 - Fixed!! Script finds all jpg,jpeg,JPG files in folder+all_subfolders and sets file modification timestamp=exif date/time. +it also writes the size of image into the filename too. (neat to know pixel size of image by just looking at the filname)
更新:10.12.2014——固定! !脚本查找文件夹+all_subfolders中的所有jpg、jpeg、jpg文件,并设置文件修改时间戳=exif日期/时间。它还将图像的大小写入文件名中。(只看文件名就能知道图像的像素大小)
Original: I been working on a script for long time, picking up info traces of info and code to use. I have managed to make a script. Run it in a folder, and it will pick up all .jpg .JPG in current and subfolders and rename them to filename. i.e: 2014_10_19_12_24_05_DSC-RX100_F5.6_f37.1mm_1T250s_ISO320.jpg
原文:我已经在一个脚本上工作了很长一段时间,收集信息的痕迹和代码来使用。我已经写好剧本了。在一个文件夹中运行它,它将在当前和子文件夹中获取所有的.jpg .jpg,并将它们重命名为filename。我。艾凡:2014 _10_19_12_24_05_dsc-rx100_f5.6_f37.1mm_1t250s_iso320.jpg
Problem
The photos may have been taken at the same time with fast shutter speed. For example:
2014_10_19_12_24_05_DSC-RX100_F5.6_f37.1mm_1T250s_ISO320.jpg (original filename P00002727.jpg)
2014_10_19_12_24_05_DSC-RX100_F5.6_f37.1mm_1T250s_ISO320.jpg (original filename P00002728.jpg)
问题:这些照片可能是在快速快门的同时拍摄的。例如:2014_10_19_12_24_05_dsc - rx100_f5.6_f37.1 mm_1mm_1t250s_iso320.jpg(原始文件名P00002727.jpg) 2014_10_19_12_05_dsc - rsc_05_100_rx100_f00006_f5.6_f5.6_27_f37.1 jpg(原始文件名为iso27320.g)
The first file is written okay, and then the second file overwrites the first one :-/
第一个文件是写好的,第二个文件重写第一个文件:-/。
If someone could help
I would like the script to have a "if file exist, the new filename should be renamed to having an increased number 01,02,03..etc.." at the end of the filename. Like this:
如果有人可以帮忙,我希望脚本有一个“如果文件存在,新的文件名应该被重命名为增加的数字01、02、03.. .等等。”是这样的:
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 (added _01,02,03 etc..)
2014_10_19_24_05_dsc - rx100_f5.6_f37.1 mm_1t250s_iso320.jpg 2014_10_10_19_12_24_05_dsc - rx100_f37.6 _f37.1 mm_1t250_iso320_01.jpg(添加_01、02、03等)
The script I'm using:
我使用的脚本:
#!/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
3 个解决方案
#1
1
Before:
之前:
mv "$s" "$NEWFILE"
use something like:
使用类似:
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
You can of'course use counter
of your script to handle sequential numbers, but this version won't recount on re-run (safer I think).
当然,您可以使用您的脚本计数器来处理顺序数字,但是这个版本不会重新运行(我认为更安全)。
#2
1
Where you create NEWFILE="$BASEDIRECTORY$x"
you want something like this:
在创建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"
repetive filenames:
长期文件名:
$ 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
NOTE: When using reverse string indexes (e.g. ${fn: -2}
) you MUST include a space before the -
sign (or place the index in parentheses (e.g. ${fn:(-2)}
).
注意:当使用反向字符串索引(例如${fn: -2})时,必须在-号之前包含一个空格(或者将索引放在圆括号中(例如${fn:(-2)}))。
When working in bash
try to utilize the tools bash provides and get away from using external applications and pipes (which each spawn a separate process and subshell of their own) such as (grep
, awk
, cut
, and '|'). There is virtually nothing bash can't do as far as string/line parsing goes utilizing its own parameter expansion / substring extraction / substring substitution and string indexes. There is nothing wrong with calling external apps from within a script, just don't use them to replace what bash already does for you.
在bash中工作时,请尝试使用bash提供的工具并避免使用外部应用程序和管道(它们各自生成一个独立的进程和自己的子shell),例如(grep、awk、cut和'|')。实际上,只要使用自己的参数展开/子字符串提取/子字符串替换和字符串索引,bash就不会做任何事情。从脚本中调用外部应用程序并没有什么错,只是不要用它们来代替bash已经为您做的事情。
Since you are working with bash
and jhead
, you may be interested in some of the ideas in this Iphone Image Rename w/jhead script. Which takes a slightly different approach to parsing jhead
image output and has a few handy functions you may make use of.
由于您正在使用bash和jhead,您可能对这个Iphone映像中的一些想法感兴趣,重命名为w/jhead脚本。它采用了一种稍微不同的方法来解析jhead映像输出,并提供了一些方便的函数。
Per our discussion in the comments, if you are feeding all filenames (including those previously incremented with _XX increments) back through the script, you will want to skip processing those files again.
在评论中我们的讨论中,如果您正在给所有的文件名(包括那些之前添加了_XX增量的文件)返回到脚本中,那么您将希望再次跳过处理这些文件。
To omit files already incremented from the main loop, you will need something like the following at the beginning of the find | while
loop:
要从主循环中删除已递增的文件,您将需要如下内容:
# 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
OK. To get to the bottom of this, and to help us to communicate more effectively, I have created a testcase script. The problem I was having is I did not have files from your camera or your files to know what all I was dealing with. This left me trying to handle all cases as broadly as possible (which should be done regardless). But the following will allow testing input files against what the output filename would be. I have left your original script contents (in comments) to show the context of where the tests are taking place and I have commented and replaced parts necessary for the testcase. Here is the script and testcases verified:
好的。为了弄清这一点,并帮助我们更有效地沟通,我创建了一个testcase脚本。我遇到的问题是我没有从你的相机或你的文件知道我在处理什么。这让我尝试尽可能广泛地处理所有案例(无论如何都应该这样做)。但是下面将允许根据输出文件名测试输入文件。我已经留下了您的原始脚本内容(在注释中),以显示测试发生的上下文,并且我已经注释并替换了testcase所需的部分。以下是经过验证的脚本和测试用例:
#!/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
existing files:
现有的文件:
$ 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
2014_10_19_12_24_05_DSC-RX100_F5.6_f37.1mm_1T250s_ISO320_AB.jpg
file renaming:
文件重命名:
$ bash newfn.sh \
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_AB.jpg \
2014_10_19_12_24_05_DSC-RX100_F5.6_f37.1mm_1T250s_ISO320_AC.jpg
file exists : 2014_10_19_12_24_05_DSC-RX100_F5.6_f37.1mm_1T250s_ISO320.jpg
new fname : 2014_10_19_12_24_05_DSC-RX100_F5.6_f37.1mm_1T250s_ISO320_03.jpg
file exists : 2014_10_19_12_24_05_DSC-RX100_F5.6_f37.1mm_1T250s_ISO320_AB.jpg
new fname : 2014_10_19_12_24_05_DSC-RX100_F5.6_f37.1mm_1T250s_ISO320_AB_01.jpg
no change : 2014_10_19_12_24_05_DSC-RX100_F5.6_f37.1mm_1T250s_ISO320_AC.jpg
#3
0
man mv(1)
has all the info you need. Here it is an example of using the numeric backup option
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~
%
Addendum
Using mv --backup=t ...
has a small defect, it uses the plain name for the last moved file, in my example above aaa1 -> bbb1.~1~
, aaa2 -> bbb1.~2~
, aaa3 -> bbb1.~3~
and (but) aaa4 -> bbb1
.
使用mv -备份= t…有一个小缺陷,它使用最后移动文件的普通名称,在我上面的示例aaa1 -> bbb1中。~ 1 ~,aaa2 - > bbb1。~ 2 ~,aaa3 - > bbb1。~3~(但)aaa4 -> bbb1。
This is perfectly logical from mv
POV and possibly less desirable for the OP.
这完全符合mv POV的逻辑,可能不太适合OP。
The script below moves the unnumbered file in its logical position (and works for any number of files that need renaming at the end of the day)
下面的脚本将未编号的文件移动到其逻辑位置(并适用于任何数量的文件,这些文件在一天结束时需要重新命名)
% 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~
%
The photos that were taken in a very short sequence are now all numbered from 1 to N
以非常短的序列拍摄的照片现在都被编号为1到N
#1
1
Before:
之前:
mv "$s" "$NEWFILE"
use something like:
使用类似:
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
You can of'course use counter
of your script to handle sequential numbers, but this version won't recount on re-run (safer I think).
当然,您可以使用您的脚本计数器来处理顺序数字,但是这个版本不会重新运行(我认为更安全)。
#2
1
Where you create NEWFILE="$BASEDIRECTORY$x"
you want something like this:
在创建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"
repetive filenames:
长期文件名:
$ 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
NOTE: When using reverse string indexes (e.g. ${fn: -2}
) you MUST include a space before the -
sign (or place the index in parentheses (e.g. ${fn:(-2)}
).
注意:当使用反向字符串索引(例如${fn: -2})时,必须在-号之前包含一个空格(或者将索引放在圆括号中(例如${fn:(-2)}))。
When working in bash
try to utilize the tools bash provides and get away from using external applications and pipes (which each spawn a separate process and subshell of their own) such as (grep
, awk
, cut
, and '|'). There is virtually nothing bash can't do as far as string/line parsing goes utilizing its own parameter expansion / substring extraction / substring substitution and string indexes. There is nothing wrong with calling external apps from within a script, just don't use them to replace what bash already does for you.
在bash中工作时,请尝试使用bash提供的工具并避免使用外部应用程序和管道(它们各自生成一个独立的进程和自己的子shell),例如(grep、awk、cut和'|')。实际上,只要使用自己的参数展开/子字符串提取/子字符串替换和字符串索引,bash就不会做任何事情。从脚本中调用外部应用程序并没有什么错,只是不要用它们来代替bash已经为您做的事情。
Since you are working with bash
and jhead
, you may be interested in some of the ideas in this Iphone Image Rename w/jhead script. Which takes a slightly different approach to parsing jhead
image output and has a few handy functions you may make use of.
由于您正在使用bash和jhead,您可能对这个Iphone映像中的一些想法感兴趣,重命名为w/jhead脚本。它采用了一种稍微不同的方法来解析jhead映像输出,并提供了一些方便的函数。
Per our discussion in the comments, if you are feeding all filenames (including those previously incremented with _XX increments) back through the script, you will want to skip processing those files again.
在评论中我们的讨论中,如果您正在给所有的文件名(包括那些之前添加了_XX增量的文件)返回到脚本中,那么您将希望再次跳过处理这些文件。
To omit files already incremented from the main loop, you will need something like the following at the beginning of the find | while
loop:
要从主循环中删除已递增的文件,您将需要如下内容:
# 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
OK. To get to the bottom of this, and to help us to communicate more effectively, I have created a testcase script. The problem I was having is I did not have files from your camera or your files to know what all I was dealing with. This left me trying to handle all cases as broadly as possible (which should be done regardless). But the following will allow testing input files against what the output filename would be. I have left your original script contents (in comments) to show the context of where the tests are taking place and I have commented and replaced parts necessary for the testcase. Here is the script and testcases verified:
好的。为了弄清这一点,并帮助我们更有效地沟通,我创建了一个testcase脚本。我遇到的问题是我没有从你的相机或你的文件知道我在处理什么。这让我尝试尽可能广泛地处理所有案例(无论如何都应该这样做)。但是下面将允许根据输出文件名测试输入文件。我已经留下了您的原始脚本内容(在注释中),以显示测试发生的上下文,并且我已经注释并替换了testcase所需的部分。以下是经过验证的脚本和测试用例:
#!/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
existing files:
现有的文件:
$ 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
2014_10_19_12_24_05_DSC-RX100_F5.6_f37.1mm_1T250s_ISO320_AB.jpg
file renaming:
文件重命名:
$ bash newfn.sh \
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_AB.jpg \
2014_10_19_12_24_05_DSC-RX100_F5.6_f37.1mm_1T250s_ISO320_AC.jpg
file exists : 2014_10_19_12_24_05_DSC-RX100_F5.6_f37.1mm_1T250s_ISO320.jpg
new fname : 2014_10_19_12_24_05_DSC-RX100_F5.6_f37.1mm_1T250s_ISO320_03.jpg
file exists : 2014_10_19_12_24_05_DSC-RX100_F5.6_f37.1mm_1T250s_ISO320_AB.jpg
new fname : 2014_10_19_12_24_05_DSC-RX100_F5.6_f37.1mm_1T250s_ISO320_AB_01.jpg
no change : 2014_10_19_12_24_05_DSC-RX100_F5.6_f37.1mm_1T250s_ISO320_AC.jpg
#3
0
man mv(1)
has all the info you need. Here it is an example of using the numeric backup option
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~
%
Addendum
Using mv --backup=t ...
has a small defect, it uses the plain name for the last moved file, in my example above aaa1 -> bbb1.~1~
, aaa2 -> bbb1.~2~
, aaa3 -> bbb1.~3~
and (but) aaa4 -> bbb1
.
使用mv -备份= t…有一个小缺陷,它使用最后移动文件的普通名称,在我上面的示例aaa1 -> bbb1中。~ 1 ~,aaa2 - > bbb1。~ 2 ~,aaa3 - > bbb1。~3~(但)aaa4 -> bbb1。
This is perfectly logical from mv
POV and possibly less desirable for the OP.
这完全符合mv POV的逻辑,可能不太适合OP。
The script below moves the unnumbered file in its logical position (and works for any number of files that need renaming at the end of the day)
下面的脚本将未编号的文件移动到其逻辑位置(并适用于任何数量的文件,这些文件在一天结束时需要重新命名)
% 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~
%
The photos that were taken in a very short sequence are now all numbered from 1 to N
以非常短的序列拍摄的照片现在都被编号为1到N