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

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.

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
  • 881
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.