3

I have about a thousand jpegs in a directory that have filenames such as

1300-Kazoo-Pkg.jpg
1314-Learn-to-Play-Piano-withKid.jpg
1314-Learn-to-Play-Piano.jpg

I want to shorten them to the numbers before the first hyphen.

I have tried using for f in *.jpg; do mv "$f" "${f/-*.}"; done but I can't figure out what to add to get done what I want done.

Any suggestions?

8
  • "I want to shorten them to the numbers before the first” can you clarify what you’d like the output to be?
    – njboot
    Commented Sep 26, 2015 at 1:52
  • Sorry, that wasn't clear. The first hyphen.
    – enano2054
    Commented Sep 26, 2015 at 2:15
  • 1
    What result do you want in the cases where you have filenames with the same prefix? One option is to just skip them. But it seems like you don’t want to do that. So, another option is to append, say, some digits, so that you end up with, e.g., 1314-1.jpg, 1314-2.jpg, etc. Is that what you want? If so, I can update my answer to show how to do that. Commented Sep 26, 2015 at 2:34
  • Yes the 1314-1.jpg and 1314-2.jpg would be great!
    – enano2054
    Commented Sep 26, 2015 at 2:37
  • OK, gimme a minute and I’ll write that up (if somebody doesn’t beat me to it). Commented Sep 26, 2015 at 2:57

1 Answer 1

4

To preserve the filename extension in the expected way, you should instead do this:

for f in *.jpg; do mv "$f" "${f/-*}.jpg"; done

That is, use ${f/-*}.jpg instead of ${f/-*.}.

To deal with the case of multiple files that have the same prefix before the dash, you can do something like this: [Note: For a better version, see the Update I’ve since added after this.]

i=0
for f in *.jpg; do
  if [ "$(ls -l ${f/-*}* | wc -l | xargs)" -gt 1 ]; then
    for g in "${f/-*}"; do
      mv "$f" "$g-$((i++)).jpg"
    done
  else
    if [[ $f == *"-"* ]]; then
      mv "$f" "${f/-*}.jpg"
    fi
  fi
done

That will give you output like this:

1300.jpg
1314-0.jpg
1314-1.jpg
1315-2.jpg
1315-3.jpg

That is, a -N suffix will get added, though with the limitation that this simple example just keeps incrementing the N value across the whole set of files instead of per-prefix.

Also note that you can safely re-run this script multiple times in the same directory and you’ll end up with the same expected filenames in the end (which I think is what you’d want, rather than it monkeying around further with any filenames that are already in the form you want).


Update

Here’s a better version that just appends 1-N suffixes to the renamed files if it finds an existing file with the same basename or same basename+N (in which case it increments by N+1 and retries).

for f in *.jpg; do
  base=${f/-*}
  if [[ -e "${base}.jpg" ]] ; then
    i=1
    while [[ -e "${base}-${i}.jpg" ]]; do
      let i++
    done
    base=$base-$i
  fi
  mv "$f" "${base}.jpg"
done

That gives output like this:

1300.jpg
1314-1.jpg
1314.jpg
1315-1.jpg
1315-2.jpg
1315.jpg
2
  • I responded to your comment.
    – enano2054
    Commented Sep 26, 2015 at 2:44
  • @patrix See my updated version, which takes sort of a completely different approach. I think it’s definitely better than what I had slapped together originally. Commented Sep 26, 2015 at 12:42

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .