Bash: sort find results using part of a filename [

2019-07-11 05:33发布

问题:

This question already has an answer here:

  • Bash and sort files in order 7 answers

I have 3 webcams set up in a building, uploading still images to a webserver. I'm using ffmpeg to encode the jpgs to mp4 video.

The directories are set up like this:

Cam1/201504
Cam1/201505
Cam2/201504
Cam2/201505
Cam3/201504
Cam3/201505

I'm using the following bash loop/ffmpeg parameters to make one video per camera, per year. This works well so far (well... except that my SSD is rapidly degrading in performance - too many simultaneous read/write operations?):

find Cam2/2013* -name "*.jpg" -print0 | xargs -0 cat | ffmpeg -f image2pipe -framerate 30 -vcodec mjpeg -i - -vcodec libx264 -profile:v baseline -level 3.0 -movflags +faststart -crf 19 -pix_fmt yuv420p -r 30 "Cam2-2013-30fps-19crf.mp4"

The individual files are named like this (confusing ffmpeg's built-in file sequencer):

Cam1_2015052413543201.jpg
Cam1_2015052413544601.jpg
Cam2_2015052413032601.jpg
Cam2_2015052413544901.jpg

I now need to create one video for an entire year across all 3 cameras, ordered by timestamp. To accomplish this, I need to sort the find results by the segment of the filename after the underscore.

What do I pipe the find output to to accomplish this? For example, the files above would be ordered like this:

Cam2_2015052413032601.jpg
Cam1_2015052413543201.jpg
Cam1_2015052413544601.jpg
Cam2_2015052413544901.jpg

Any help is very much appreciated!

回答1:

sort

sort -t '_' -nk2

-t '_' # specifices that the field seperator should be an underscore

-nk2 # start sorting from the second field (after the underscore)..n sort according to numerical value/timestamp

output

Cam2_2015052413032601.jpg
Cam1_2015052413543201.jpg
Cam1_2015052413544601.jpg
Cam2_2015052413544901.jpg

pipe sort to find command like

sort -t '_' -nk2 --files0-from=-


回答2:

Use sort with the --key option. See your man page of sort for details of the key format. Generally (for both coreutils and BSD sort) it should be F[.C][OPTS][,F[.C][OPTS]], where F is for field and C is for character position. Here you want to sort from the 5th character of the first field, so --key=1.5 will do:

> echo -e 'Cam1_2015052413543201.jpg\nCam1_2015052413544601.jpg\nCam2_2015052413032601.jpg\nCam2_2015052413544901.jpg' | sort --key=1.5
Cam2_2015052413032601.jpg
Cam1_2015052413543201.jpg
Cam1_2015052413544601.jpg
Cam2_2015052413544901.jpg

Here you seem to have not only basenames in the output of find, but relative paths with path segments like Cam1/201505/ prepended, but you can still count the number of characters and hence write the appropriate keydef. For instance, say the paths for the images in the example above are

Cam1/201505/Cam1_2015052413543201.jpg
Cam1/201505/Cam1_2015052413544601.jpg
Cam2/201505/Cam2_2015052413032601.jpg
Cam2/201505/Cam2_2015052413544901.jpg

Then

sort --key=1.17

will give you the correct order

Cam2/201505/Cam2_2015052413032601.jpg
Cam1/201505/Cam1_2015052413543201.jpg
Cam1/201505/Cam1_2015052413544601.jpg
Cam2/201505/Cam2_2015052413544901.jpg