Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I pass all arguments with xargs in middle of command in linux

Tags:

linux

xargs

I want to pass all the files as a single argument on Linux but I am not able to do that.

This is working

ls | sort -n | xargs  -i pdftk  {} cat output combinewd2.pdf 

This passes a single argument per command, but I want all in one command.

like image 826
user2027303 Avatar asked Feb 01 '13 03:02

user2027303


People also ask

How do you use xargs with multiple arguments?

Two Types of Commands Using Multiple Arguments Commands can have multiple arguments in two scenarios: All command arguments – COMMAND ARG1 ARG2 ARG3. Option arguments – for example, COMMAND -a ARG1 -b ARG2 -c ARG3.

How do you pass arguments to xargs?

The -c flag to sh only accepts one argument while xargs is splitting the arguments on whitespace - that's why the double quoting works (one level to make it a single word for the shell, one for xargs).

What does the xargs command do in Linux?

The xargs command builds and executes commands provided through the standard input. It takes the input and converts it into a command argument for another command. This feature is particularly useful in file management, where xargs is used in combination with rm , cp , mkdir , and other similar commands.

Does xargs run in parallel?

xargs will run the first two commands in parallel, and then whenever one of them terminates, it will start another one, until the entire job is done. The same idea can be generalized to as many processors as you have handy. It also generalizes to other resources besides processors.


2 Answers

Use -I option:

echo prefix | xargs -I % echo % post 

Output:

prefix post 
like image 164
Hongbo Liu Avatar answered Nov 07 '22 16:11

Hongbo Liu


This is one way to do it

pdftk $(ls | sort -n) cat output combinewd2.pdf 

or using backtick

pdftk `ls | sort -n` cat output combinewd2.pdf 

For example, if the filenames are 100, 2, 9, 3.14, 10, 1 the command will be

pdftk 1 2 3.14 9 10 100 cat output combinewd2.pdf 

To handle filenames with spaces or other special characters consider this fixed version of @joeytwiddle's excellent answer (which does not sort numerically, see discussion below):

#-- The following will handle special characters, and #   will sort filenames numerically #   e.g. filenames 100, 2, 9, 3.14, 10, 1 results in  #      ./1 ./2 ./3.14 ./9 ./10 ./100 # find . -maxdepth 1 -type f -print0 |   sort -k1.3n -z -t '\0' |   xargs -0 sh -c 'pdftk "$@" cat output combinewd2.pdf' "$0" 

Alternatives to xargs (bash specific)

xargs is an external command, in the previous example it invokes sh which in turn invokes pdftk.

An alternative is to use the builtin mapfile if available, or use the positional parameters. The following examples use two functions, print0_files generates the NUL terminated filenames and create_pdf invokes pdftk:

print0_files | create_pdf combinewd2.pdf 

The functions are defined as follows

#-- Generate the NUL terminated filenames, numerically sorted print0_files() {     find . -maxdepth 1 -type f -print0 |         sort -k1.3n -z -t '\0' } 
#-- Read NUL terminated filenames using mapfile create_pdf() {     mapfile -d ''     pdftk "${MAPFILE[@]}" cat output "$1" } 
#-- Alternative using positional parameters create_pdf() {     local -r pdf=$1     set --     while IFS= read -r -d '' f; do set -- "$@" "$f"; done     pdftk "$@" cat output "$pdf" } 

Discussion

As pointed out in the comments the simple initial answer does not work with filenames containing spaces or other special characters. The answer by @joeytwiddle does handle special characters, although it does not sort numerically

#-- The following will not sort numerically due to ./ prefix, #   e.g. filenames 100, 2, 9, 3.14, 10, 1 results in  #      ./1 ./10 ./100 ./2 ./3.14 ./9 # find . -maxdepth 1 -type f -print0 |   sort -zn |   xargs -0 sh -c 'pdftk "$@" cat output combinewd2.pdf' "$0" 

It does not sort numerically due to each filename being prefixed by ./ by the find command. Some versions of the find command support -printf '%P\0' which would not include the ./ prefix. A simpler, portable fix is to add the -d, --dictionary-order option to the sort command so that it considers only blank spaces and alphanumeric characters in comparisons, but might still produce the wrong ordering

#-- The following will not sort numerically due to decimals #   e.g. filenames 100, 2, 9, 3.14, 10, 1 results in  #      ./1 ./2 ./9 ./10 ./100 ./3.14 # find . -maxdepth 1 -type f -print0 |   sort -dzn |   xargs -0 sh -c 'pdftk "$@" cat output combinewd2.pdf' "$0" 

If filenames contain decimals this could lead to incorrect numeric sorting. The sort command does allow an offset into a field when sorting, sort -k1.3n, one must be careful though in defining the field separator if filenames are to be as general as possible, fortunately sort -t '\0' specifies NUL as the field separator, and the find -print0 option indicates NUL is to be used as the delimiter between filenames, so sort -z -t '\0' specifies NUL as both the record delimiter and field separator-- each filename is then a single field record. Given that, we can then offset into the single field and skip the ./ prefix by specifying the 3rd character of the 1st field as the starting position for the numeric sort, sort -k1.3n -z -t '\0'.

like image 22
amdn Avatar answered Nov 07 '22 15:11

amdn