1

This question already has an answer here:

I have a program that generates a variable number of pictures, ordered like that: 1.jpg, 2.jpg [...] 10.jpg..etc

I can't use *.jpg as input because the 10 will be processed before 2, 3, etc. so I want to use:

convert page_{1..$N}.jpg out.pdf

but does not work. How should the command be?

marked as duplicate by Jesse_b, Anthony Geoghegan, Jeff Schaller, sam, garethTheRed Dec 31 '17 at 8:55

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

5

You could store the filenames in an array, generating them with seq:

pages=( $(printf 'page_%d.jpg\n' $(seq $N)) )
convert "${pages[@]}" out.pdf
  • seq is not POSIX for that reason I didn't use it in the first place but thanks for the tip. – Smeterlink Dec 31 '17 at 18:47
4

Because brace expansion is performed before variable substitution, {1..$n} will not work as one would like and there are good reasons to avoid eval. A simple solution is to fix the filenames so that they sort in order.

Consider these files:

$ ls
page_10.jpg  page_1.jpg  page_2.jpg  page_3.jpg  page_4.jpg  page_5.jpg  page_6.jpg  page_7.jpg  page_8.jpg  page_9.jpg

By prepending zeros to the single-digit file names, we can make them sort as you want:

$ for f in ./page_[0-9].jpg; do mv "$f" "./page_0${f#./page_}"; done
$ ls
page_01.jpg  page_02.jpg  page_03.jpg  page_04.jpg  page_05.jpg  page_06.jpg  page_07.jpg  page_08.jpg  page_09.jpg  page_10.jpg

Now you can use:

convert *.jpg out.pdf

Converting 2 digits to 3

As smeterlink points out, the above can be extended to convert 2 digits to 3:

for f in ./page_[0-9][0-9].jpg; do mv "$f" "./page_0${f#./page_}"; done

As an example, and using the files as above:

$ for f in ./page_[0-9][0-9].jpg; do mv "$f" "./page_0${f#./page_}"; done
$ ls
page_001.jpg  page_002.jpg  page_003.jpg  page_004.jpg  page_005.jpg  page_006.jpg  page_007.jpg  page_008.jpg  page_009.jpg  page_010.jpg
  • 1
    +1. rename can also be used for this. e.g. rename 's/^(\d+)\.png$/sprintf("%03i.png", $1)/e' *.png. This requires the perl rename utility (sometimes known as file-rename), not the much less capable rename in util-linux. – cas Dec 31 '17 at 1:53
  • @cas Yes, for my own use, perl's rename is my first choice. If it weren't for some distributions having chosen the util-linux utility as their default and the naming uncertainty (rename vs file-rename vs prename) on other distributions, it would be what I would recommend here. It would be nice if the distributions could sort this out and develop a standard. – John1024 Dec 31 '17 at 3:05
  • 1
    IMO the perl rename is standard, util-linux's rename is just an impostor :) I've just got into the habit of mentioning that there are two entirely different programs called rename whenever I refer to it. The fact that the perl rename can do things like this (regexp replace with a sprintf function call) is why i don't even consider util-linux's rename to be at all useful. – cas Dec 31 '17 at 3:06
  • Thanks great. If there were 3 numeric digits it's very similar: for f in ./page_[0-9][0-9].jpg; do mv "$f" "./page_0${f#./page_}"; done – Smeterlink Dec 31 '17 at 18:53
  • @Smeterlink Yes, exactly right. (I've just added that to the answer.) – John1024 Dec 31 '17 at 19:19
2

Brace expansion is performed before variable substitution thus you need eval if you want it the other way round:

eval convert page_{1..$N}.jpg out.pdf

An alternative is to sort the expanded file names:

convert $(echo page_*.jpg | tr ' ' '\n' | sort -n -k 2 -t _) out.pdf
  • 1
    Q is ambiguous but if the number isn't at the beginning of the line you need e.g. sort -nk1.6 (or -k1.6n). – dave_thompson_085 Dec 31 '17 at 6:15
  • @HaukeLaging Second example does not work, results in page_1.jpg page_10.jpg page_2.jpg page_3.jpg page_4.jpg page_5.jpg page_6.jpg page_7.jpg page_8.jpg page_9.jpg – Smeterlink Dec 31 '17 at 18:55
  • @Smeterlink That is very strange. Not only because it does work for me but because -n is numeric sort. Are you using GNU sort? Mine is sort (GNU coreutils) 8.28 – Hauke Laging Dec 31 '17 at 18:59
  • @HaukeLaging yes I'm using GNU Coreutils. The sort only works if the file starts with a number like 1.png 10.png 2.png but doesn't if it starts with a letter which is the case. Did you even try the command yourself is you're just guessing? Post a screenshot. – Smeterlink Jan 3 '18 at 10:40
  • @Smeterlink Indeed, I was sloppy and used not the correct file names for my test case. I have corrected the sort call. – Hauke Laging Jan 3 '18 at 22:48

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