AFAICT, it looks like you want to change the space in the date string to a -
character?
That's actually pretty easy....but, first, there are some problems with that shell script. Firstly, it uses backticks for command substitution instead of $(
and )
. Secondly, it uses grep unnecessarily (sed can do what grep's doing here). Thirdly, the regex search and replace you want to do is much easier to do in two steps than one (first remove the "File date" part of the line, then modify the remaining date string).
Here's an improved version of that script:
for i in *.JPG; do
j=$(jhead "$i" | sed -n -E '/^File date/ { s/^File date +: +//; s/ /-/p}').jpg
echo mv -i "$i" "$j"
done
In English: the output of the jhead
command is piped into sed. The sed option -n
tell sed not to output any lines unless told to by a p
(print) statement. The -E
option tells it to use Extended Regular Expressions (ERE) instead of Basic Regular Expressions (BRE)...this is mostly so I can use the +
modifier to match one-or-more spaces.
The sed script itself first checks if the line begins with "File date". If it does, it executes a block of sed commands (i.e. two or more commands wrapped in {
and }
).
The first command in the block removes "File date" followed by one-or-more space, a colon, and then one-or-more spaces from the line. This will result in the line containing just the date.
The second command changes the first (and only) space character with a dash -
. There is a p
at the end of this s///
command, which tells sed to print the modified line.
Example run:
$ ls -l *.JPG
-rw-r--r-- 1 cas cas 1110176 Oct 20 14:04 abc.JPG
-rw-r--r-- 1 cas cas 1132711 Oct 20 14:04 def.JPG
-rw-r--r-- 1 cas cas 1061121 Oct 20 14:04 ghi.JPG
$ for i in *.JPG; do
j="$(jhead "$i" |sed -n -E '/^File date/ { s/^File date +: +//; s/ /-/p }').jpg"
echo mv -i "$i" "$j"
done
mv -i abc.JPG 2021:10:20-14:04:08.jpg
mv -i def.JPG 2021:10:20-14:04:09.jpg
mv -i ghi.JPG 2021:10:20-14:04:10.jpg
BTW, this script is not particularly safe. It doesn't, for example, take into account the fact that two different jpeg files can have exactly the same timestamp.
Something like the following is far from perfect, but would be safer/better:
for i in *.JPG; do
j="$(jhead "$i" | sed -n -E '/^File date/ { s/^File date +: +//; s/ /-/p }')"
c=1
while [ -e "$j-$c.jpg" ] ; do
let c+=1
done
j="$j-$c"
mv -iv "$i" "$j.jpg"
done
(note: this version actually renames files, it doesn't just echo
what it would do. This was necessary for testing because if it didn't do that, it wouldn't know when to increment the counter variable, $c
)
Example output:
renamed 'abc.JPG' -> '2021:10:20-14:04:08-1.jpg'
renamed 'def.JPG' -> '2021:10:20-14:04:08-2.jpg'
renamed 'ghi.JPG' -> '2021:10:20-14:04:08-3.jpg'
BTW, if you're likely to have more than 9 jpeg files with the same timestamp, you can use printf
to make sure the counter is two or three digits and zero-padded. e.g.
for i in *.JPG; do
j="$(jhead "$i" | sed -n -E '/^File date/ { s/^File date +: +//; s/ /-/p }')"
c=1
while [ -e "$(printf "%s-%03i.jpg" "$j" "$c")" ] ; do
let c+=1
done
j="$(printf "%s-%03i.jpg" "$j" "$c")"
mv -iv "$i" "$j"
done
renamed 'abc.JPG' -> '2021:10:20-14:04:08-001.jpg'
renamed 'def.JPG' -> '2021:10:20-14:04:08-002.jpg'
renamed 'ghi.JPG' -> '2021:10:20-14:04:08-003.jpg'
RE: your questions about the caret ^
character.
Outside of a bracket expression, it's a beginning-of-line anchor - e.g. ^File date
matches "File date" only at the start of a line.
Inside a bracket expression, it negates/inverts the meaning of the expression. e.g. where [A-Z]
matches all characters from A to Z, [^A-Z]
matches all characters which are not between A and Z.
:
colons are disallowed--copy/paste into thesave
dialog box results in automatic conversion of:
colons into-
hyphens. – jubilatious1 Oct 20 '21 at 04:28