1

I am trying to find files that match time=* and then need to display it by sorting it numerically.
The result file names would be :

first/path/time=001.jpg
first/path/time=002.jpg
second/path/time=001.jpg
...

which I want to see as,

first/path/time=001.jpg
second/path/time=001.jpg
first/path/time=002.jpg
...

sorted numerically with respect to the 3 digits on file name.

For now, i tried find . -name time=* | rev | sort | rev

which does work for single digits but with numbers like 019 021 it does not work.

Full path would be something like,

path/to/folder1/alpha=0.1_beta=0.2_gamma=1.0/time=001.jpg
path/to/folder1/alpha=0.1_beta=0.2_gamma=0.1/time=001.jpg
path/to/folder2/alpha=0.1_beta=0.2_gamma=0.1/time=001.jpg
.
.
.

I think it would be easiest if the files could be sorted using only last 7 characters. 001.jpg 010.jpg... however sadly sort does not support support negative indexing to get last 6 characters :(

jkhadka
  • 203
  • 2
  • 8
  • 1
    (1) What OS? Looks like some Unix, still you should make it clear. (2) Quote the pattern, [or else](https://superuser.com/q/1217773/432690)... – Kamil Maciorowski Jan 23 '18 at 10:23
  • hey, Its Linux and what do you mean by quote the pattern? – jkhadka Jan 23 '18 at 10:29
  • I mean exactly what my answer says under [this link I have already gave you](https://superuser.com/q/1217773/432690). – Kamil Maciorowski Jan 23 '18 at 10:31
  • hi thanks, but that was not the problem with me. I dont have `time=*` file in current directory to have that problem. But definitely a new thing to learn! thanks again! i will keep this in find for future. – jkhadka Jan 23 '18 at 11:45
  • @KamilMaciorowski oh no. i just meant `time=001.jpg` `time=002.jpg` and so on. – jkhadka Jan 23 '18 at 13:57

3 Answers3

2

This should do:

find . -name 'time=*' | sort -t= -k3

But this is a more safe sorting, as per Kamil Maciorowski's comment:

perl -C -F= -wnle 'push @a,[$_,split(/\./,$F[-1])]; END {$,="\n"; print map{$$_[0]} sort{$$a[1]<=>$$b[1]} @a}'

Use it in the pipeline afer find instead of sort in the first one.

  • Unless you encounter `third/path/a=foo/bar/...`. – Kamil Maciorowski Jan 23 '18 at 12:58
  • @KamilMaciorowski `I am trying to find files that match time=*` says the question. –  Jan 23 '18 at 13:00
  • 1
    Add `third/path/a=foo/bar/time=001.jpg` to the set provided by the OP. It will end up after `first/path/time=002.jpg` because of the extra `=`. Your answer may or may not be sufficient for the OP, it's good to know its limitations. Maybe the other answer is flawed as well; I don't know `ruby` enough to tell. – Kamil Maciorowski Jan 23 '18 at 13:09
  • hi @tomasz, thanks for your reply but as @Kamil says it actually does not work for me as my actual path is something like `first/path/parameter=1/time=001.jpg` `first/path/parameter=0.1/time=001.jpg` `second/path/parameter=1/time=001.jpg` ... :( – jkhadka Jan 23 '18 at 13:51
  • @hadik If that's regular and as you present, then change `-k2` to `-k3`. –  Jan 23 '18 at 14:12
  • @tomasz cool solution this actually worked. nice combination of -t and -k, I do have regular names, so this is perfect thanks ! :) – jkhadka Jan 23 '18 at 14:16
  • Hah, did not know that option of `sort`. +1 – mvw Jan 23 '18 at 14:49
  • @hadik Welcome. I added Perl too for the weird cases. –  Jan 23 '18 at 15:30
1

A quickie with left-overs I picked from the command line :-)

find . -name time="*" -exec ruby -e "s='{}'; puts s.split('=')[-1].split('.')[0]+s" \; |
sort -n | colrm 1 3

Explanation:

My friend Ruby stores the path string given by find as {} and stores it into a variable s. Then she splits the string along = characters and keeps the last part (index -1 in the result array), e.g. 002.jpg. Then she splits this string on . characters and keeps the first part (index 0 in the result array), assuming the files are named ddd.<ext>, which results is the three digit number part, e.g. 002.

Finally she prints this and adds the original path string. This would give:

002./alpha=0.1_beta=0.2_gamma=1.0/path/time=002.jpg
001./alpha=0.1_beta=0.2_gamma=1.0/path/time=001.jpg
021./alpha=0.1_beta=0.2_gamma=0.1/path/time=021.jpg
001./alpha=0.1_beta=0.2_gamma=0.1/path/time=001.jpg
019./alpha=0.1_beta=0.2_gamma=0.1/path/time=019.jpg

The additional pipe commands sort the output numerically (sort -n) and finally remove the first three columns of the output (colrm 1 3).

Example:

test$ find . -name time="*" -exec ruby -e "s='{}'; puts s.split('=')[-1].split('.')[0]+s" \; 
| sort -n | colrm 1 3
./alpha=0.1_beta=0.2_gamma=0.1/path/time=001.jpg
./alpha=0.1_beta=0.2_gamma=1.0/path/time=001.jpg
./alpha=0.1_beta=0.2_gamma=1.0/path/time=002.jpg
./alpha=0.1_beta=0.2_gamma=0.1/path/time=019.jpg
./alpha=0.1_beta=0.2_gamma=0.1/path/time=021.jpg
mvw
  • 851
  • 5
  • 12
  • this one has the same problem as the other solution suggested by @tomasz . as my path contains multiple `=` this sorts through the numbers after first `=` and then the second `=` and so on. So my files are actually not sorted as i like. – jkhadka Jan 23 '18 at 14:01
  • OK, can I assume the last "="? (Note that I updated the index from "1" to "-1") – mvw Jan 23 '18 at 14:03
  • @hadik Note that you added that requirement about multiple "=" after I posted my first version. – mvw Jan 23 '18 at 14:25
  • It looks like Ruby's called for each file found. –  Jan 23 '18 at 15:47
  • Yes, this was a quick hack. It is not optimized. – mvw Jan 23 '18 at 16:04
  • @mvw thanks for the reply. this works now but solution by tomasz was easiest for my problem :) – jkhadka Jan 23 '18 at 20:56
  • 1
    At least I had `f1rst p0st` :-) – mvw Jan 23 '18 at 20:58
1

Assuming no path is insane enough to require find ... -print0:

find . -type f -name "time=*" | awk -F '=' '{ print $NF "=" $0 }' | sort -n | cut -d "=" -f 2-

I used awk to extract parts behind the last =, it outputs full lines with additional relevant part in front, separating by additional =. E.g.:

001.jpg=path/to/folder1/alpha=0.1_beta=0.2_gamma=1.0/time=001.jpg

These are sorted numerically with sort. Then cut extracts parts after this additional (first) =; these are the original paths.

There are exactly four processes created: find, awk, sort, cut. Alternatives that use the syntax of find ... -exec some_tool ... \; create one some_tool process per matching file.

Kamil Maciorowski
  • 69,815
  • 22
  • 136
  • 202