0

I am trying to execute a command to match a certain subset of files in a directory. All of the files have a name timestamp.jpg, with roughly (but not exactly) 30 minutes between each file.

Based on this question and answer, I came up with this command (using echo to test):

for x in *([1510852838790,1510898258530]).jpg; do echo $x; done

However, this outputs the following (note the input numbers marked with ****):

1510770572978.jpg
1510770810272.jpg
1510772133873.jpg
1510772378293.jpg
1510772979803.jpg
1510773223237.jpg
1510852838790.jpg****
1510852959075.jpg
1510853079321.jpg
1510853808012.jpg
1510855019583.jpg
1510855380099.jpg
1510855983715.jpg
1510857313787.jpg
1510858282007.jpg
1510858889310.jpg
1510859009339.jpg
1510859253091.jpg
1510870852822.jpg
1510871097118.jpg
1510871335799.jpg
1510871703808.jpg
1510871823158.jpg
1510872311110.jpg
1510872553750.jpg
1510872917378.jpg
1510873159981.jpg
1510875721755.jpg
1510877181978.jpg
1510877301888.jpg
1510878157813.jpg
1510878278033.jpg
1510878522553.jpg
1510879250080.jpg
1510879738575.jpg
1510879859397.jpg
1510880105392.jpg
1510880717151.jpg
1510880957839.jpg
1510881325005.jpg
1510881570373.jpg
1510881811325.jpg
1510882295590.jpg
1510882785823.jpg
1510883275381.jpg
1510885101702.jpg
1510885222385.jpg
1510885711900.jpg
1510887172253.jpg
1510887292977.jpg
1510887538312.jpg
1510888029878.jpg
1510889975298.jpg
1510890221372.jpg
1510890709993.jpg
1510890830832.jpg
1510890951888.jpg
1510891193150.jpg
1510891313575.jpg
1510891922503.jpg
1510892537090.jpg
1510892900397.jpg
1510893021713.jpg
1510893385557.jpg
1510893992777.jpg
1510895212923.jpg
1510895333595.jpg
1510895819713.jpg
1510897039331.jpg
1510897159572.jpg
1510898133110.jpg
1510898258530.jpg****
1510900807071.jpg
1510900927933.jpg
1510902272277.jpg
1510902393272.jpg
1510902998172.jpg
1510903851131.jpg
1510905309558.jpg
1510905557228.jpg
1510907015107.jpg
1510907751301.jpg
1510907877003.jpg
1510907992905.jpg
1510908113731.jpg
1510908598199.jpg
1510908719029.jpg
1510909570015.jpg
1510909811208.jpg
1510909931529.jpg
1510910181722.jpg
1510911388852.jpg
1510911513951.jpg
1510911879905.jpg
1510912727850.jpg
1510913088390.jpg
1510913818319.jpg
1510915397801.jpg
1510917103919.jpg
1510917711228.jpg
1510917832327.jpg
1510917953273.jpg
1510918319775.jpg
1510918803832.jpg
1510918929550.jpg
1510919172181.jpg
1510919293195.jpg
1510919898053.jpg
1510922089190.jpg
1510922579951.jpg
1510923308092.jpg
1510923550590.jpg
1510923793010.jpg
1510925011829.jpg
1510925137958.jpg
1510925987153.jpg
1510927083913.jpg
1510927812212.jpg
1510928298155.jpg
1510928910223.jpg
1510929031559.jpg
1510930370780.jpg
1510930733981.jpg
1510930981902.jpg
1510932080591.jpg
1510932809212.jpg
1510933290952.jpg
1510933903131.jpg
1510935121827.jpg
1510935237921.jpg
1510935725717.jpg
1510937189535.jpg
1510937919235.jpg
1510938283032.jpg
1510938895279.jpg
1510939137978.jpg
1510939501755.jpg
1510939992901.jpg

The output list contains 138 file names out of the 798 files in the directory, but it contains additional files before the first input number and after the second input number. Why is this and how do I correct it?

  • Your title says you're trying to match non-consecutive filenames, but then you ask about the mysterious files showing up outside of the expected range, and also mention a 30-minute approximate gap. Are you trying to find files that ... do ... or don't ... have the 30-minute gap, no matter where in the sequence they are? – Jeff Schaller Nov 17 '17 at 19:56
  • @A.B I was going to point that out, but the glob expansion is the same in both shells. – Jeff Schaller Nov 17 '17 at 19:57
  • @JeffSchaller I'm trying to find all files between the input numbers – lucasvw Nov 17 '17 at 20:03
2

[1510852838790,1510898258530] is a standard glob operator that matches one character in the set of characters. [ab,c] matches either a, b, , or c. So [1510852838790,1510898258530] is the same as [,01235789] or [,0-357-9]. That is, it matches commas or decimal digits other than 4 and 6.

*(...) is a Korn shell glob operator (also supported by zsh -o kshglob and bash -O extglob) that matches 0 or more ....

So *([1510852838790,1510898258530]).jpg matches any sequence of ,01235789 characters followed by .jpg.

If you wanted to match any string that consists of a decimal number ranging between 1510852838790 and 1510898258530, you'd need the <x-y> glob operator of the zsh shell:

printf '%s\n' <1510852838790-1510898258530>.jpg

The answer you're linking to refers to another feature of the zsh shell (again not bash): the [x,y] glob qualifier.

Glob qualifiers is a (...) part that is added to the end of a glob to add some criteria other than those based on the name.

For instance, *.jpg(.) is *.jpg but limited to regular files (excluding directories, symlinks, sockets, fifos...)

*.jpg([5,10]) is the 5th to 10th files in the list of files that match *.jpg (sorted lexically).

Note that the zsh glob qualifiers do conflict with kshglob. It you want to use kshglob (but generally you wouldn't unless you want to interpret code intended for ksh as zsh extendedglobs are generally better than ksh ones), you generally want to also disable the bareglobqual option (or use the ksh emulation mode with emulate ksh that would take care of that and also enable more ksh-like behaviours).

The equivalent of ksh's *(x) in zsh extended globs is x# (like regexp x* except that in globs * is used for something else).

bash doesn't have the <x-y> glob operator, nor glob qualifiers. In bash, you can do:

zsh -c "printf '%s\n' <1510852838790-1510898258530>.jpg"

Or you could print all number.jpg files and post process the output with awk:

shopt -s extglob
printf '%s\n' *([0-9]).jpg |
  awk -F. '$1 >= 1510852838790 && $1 <= 1510898258530'

Anyway, if you're going to try and find gaps in the sequence of numbers, you'll probably want to use awk anyway.

Like (back to using zsh):

print -l <->.jpg(n) | awk -F. '
  {diff = ($0 - prev) / 1000 / 60}
  NR > 1 && (diff < 29 || diff > 31) {print $0, "diff=" diff}
  {prev = $0}'
  • So if I'm reading this correctly, there's no good way to do what I am trying to with bash? – lucasvw Nov 17 '17 at 20:09
  • @lucasvw, see edit. – Stéphane Chazelas Nov 17 '17 at 20:22
  • Ok, thanks. I was mostly asking about bash to make sure I understood your answer. – lucasvw Nov 17 '17 at 20:34
0

If your filenames are all timestamps, you could compare them inside an arithmetic context (( )). This gets all numerically named jpg files, strips the extension, and compares them to your upper and lower bounds:

#!/bin/bash

shopt -s extglob

for f in *([0-9]).jpg; do
   timestamp="${f%%.*}"
   (( "$timestamp" >= 1510852838790 && "$timestamp" <= 1510898258530 )) && echo "$f"
done

exit

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.