0

Let's say, I have a folder with hundreds or thousands of files, all named after the following schema:

<random number of variable length>_<date code in YYYYMMDD format>.jpg

Example:

73923_20180927.jpg
4457582_20180927.jpg
   ...
18733557_20190401.jpg
23573_20190401.jpg
   ...

What I expect my bash script to do, is printing a list of those date codes, i.e.

20180927
20190401
   ...

That sounds like an easier task that it is. Since the schema is always the same, I already achieved to apply string manipulation in order to only print the required part of the file names. However, I'm still figuring out, how to print each date only once.

Is there a neat way out of this?

3

Assuming the filenames all match the pattern ./*_*.jpg:

for name in ./*_*.jpg; do
    name=${name##*_}              # 4457582_20180927.jpg --> 20180927.jpg
    printf '%s\n' "${name%.jpg}"  # 20180927.jpg --> 20180927
done | sort -u

This iterates over all the names. For each name, it then removes the longest prefix string matching *_. It then outputs the remaining string with with the .jpg suffix removed.

All strings are then sorted in such a way that only a list of unique strings are outputted at the end.

If there is a risk that the directory may be empty, you should set the nullglob shell option before the loop (shopt -s nullglob). This would make the loop not run at all instead of running once with the unexpanded globbing pattern in $name.


For no particular reason, this is how to do it without sort:

declare -A skip=()

for name in ./*_*.jpg; do
    key=${name##*_}    # 4457582_20180927.jpg --> 20180927.jpg
    key=${key%.jpg}    # 20180927.jpg --> 20180927
    if [[ ! -v skip[$key] ]]; then
        printf '%s\n' "$key"
        skip[$key]=1
    fi
done

Here, I keep track of what strings have already been outputted as keys in an associative array, skip. A string will not be outputted if it corresponds to a key in the array.

| improve this answer | |
1

Assuming there are really no improper file names, run in that directory:

ls -U | awk '-F[_.]' '{ print $2 }' | sort | uniq
| improve this answer | |
  • If you're going to use awk, couldn't you skip the sort|uniq and just use something like '!seen[$2]++ { print $2 }' ? – steeldriver Apr 5 at 18:39
  • @steeldriver I would have had to explain that more! I also considered asort(), but went for the standard utilities and a sorted output, partly influenced by your own previous comment. Skins and Cats. – Paul_Pedant Apr 5 at 18:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.