0

Context: Catalina = zsh (preferred) or 16.04 Ubuntu = bash

A qpdf example indicates:

# To merge (concatenate) all the pages of a list of PDF files and save the result as a new PDF:
qpdf --empty --pages <file1.pdf> <file2.pdf> <file3.pdf> -- <output.pdf>

A set of .pdf files (with spaces in filenames), in a particular directory, are to be concatenated:

# Concatenate Drafts file to ../concatDrafts.pdf   (76 pdf files)
# https://stackoverflow.com/a/53754681/4953146
qpdf --empty --pages *.pdf -- out.pdf

Although qpdf command is concatenates .pdf files, the reverse order of the .pdf files is to be concatenated. The order of the files to be processed is returned by:

ls -r.pdf

To handle spaces in the .pdf file names: xargs research indicates the need for:

ls -r *.pdf | xargs -E '\n'

What is the the thought process to arrive at a command the pipes the output of ls into the qpdf command?

2

3 Answers 3

3

In zsh, it would just be:

qpdf --empty --pages ./*.pdf(On) -- output.pdf

Where On is a glob qualifier to order the glob expansion in reverse (capital O, lower case would be for straight) order by name.

You could also add the n glob qualifier for that by-name ordering to be numerical:

qpdf --empty --pages ./*.pdf(nOn) -- output.pdf

Compare:

$ print -r ./*.pdf(On)
./file3.pdf ./file2.pdf ./file1.pdf ./file11.pdf ./file10.pdf
$ (LC_ALL=C; print -r ./*.pdf(On))
./file3.pdf ./file2.pdf ./file11.pdf ./file10.pdf ./file1.pdf

(in lexical order, file10.pdf comes before file2.pdf, and even before file1.pdf in locales where punctuation (here .) is ignored in first approximation when comparing strings).

With:

$ print -r ./*.pdf(nOn)
./file11.pdf ./file10.pdf ./file3.pdf ./file2.pdf ./file1.pdf

The file10.pdf comes after file3.pdf because with n, sequences of decimal digits are compared numerically (that's similar to what is done by GNU ls -v or GNU sort -V).

4
  • Thank you for the elegant solution & concise response. I believe that the (On) glob qualifier reverses the order & solves the problem. I do not understand the (nOn) glob qualifier numerical ordering: please consider posting a link to a simple concrete example.
    – gatorback
    Nov 2, 2020 at 16:27
  • @gatorback, see edit. Nov 2, 2020 at 16:37
  • The Chazelas solution is elegant (minimalism) and the example is very helpful to those learning the craft.
    – gatorback
    Nov 2, 2020 at 20:09
  • Follow-on question regarding ./ posted: unix.stackexchange.com/questions/617789/…
    – gatorback
    Nov 3, 2020 at 13:13
1

You can use answers to How to reverse shell arguments? to reverse what *.pdf expands to. First store this as positional parameters of the shell:

set -- *.pdf

Then use any good answer to the linked question. I choose this one:

flag=''; for a in "$@"; do set -- "$a" ${flag-"$@"}; unset flag; done

Now "$@" expands to what you want. Use it with your desired command:

qpdf --empty --pages "$@" -- out.pdf

If you don't want to lose old positional parameters then run the three commands in a subshell.

1

(For a GNU bash shell)

You can use tac to reverse the list of the arguments going to xargs. For the qpdf command you run, we have to combine two more arguments: -- and out.pdf at the end.

Here using the newline as the arguments separator, that means filenames with newlines are not handled:

printf "%s\n" "out.pdf" "--" *.pdf | tac | xargs -d'\n' qpdf --empty --pages

And here for any filenames, using the null separator:

printf "%s\0" "out.pdf" "--" *.pdf | tac -s $'\0' | xargs -0 qpdf --empty --pages

I tested (GNU Bash shell on Linux), it concatenated the files in the expected reversed order.

5
  • Please see my test results i.stack.imgur.com/5VsAE.png
    – gatorback
    Nov 1, 2020 at 18:14
  • I see command not found: tac ! BTW for zsh, (I think) there could be a direct glob syntax.
    – thanasisp
    Nov 1, 2020 at 18:16
  • 1
    brew install coreutils installed to provide tac
    – gatorback
    Nov 1, 2020 at 18:18
  • same errors returned after installing tac Filenames has spaces which may not play nicely with tac
    – gatorback
    Nov 1, 2020 at 18:20
  • Filenames with spaces are handled. Please see edited answer for where this answer works. You need GNU utilities, xargs and tac, to work.
    – thanasisp
    Nov 1, 2020 at 19:38

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.