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

落花浮王杯 提交于 2019-11-27 14:45:07

问题


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.


回答1:


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

As pointed out in the comments this will not work on filenames containing spaces. In that case you could use eval

eval pdftk $(while IFS= read -r file; do
    echo \"$file\"
done < <(ls | sort -n)) cat output combinewd2.pdf

Suppose there are two files named " 0 foo " and " 1 bar " then the result of eval would be the desired command, with the file names in double quotes:

pdftk " 0 foo " " 1 bar " cat output combinewd2.pdf

If the filenames might contain newlines, then use find command, see discussion by @joeytwiddle in the comments of @andrewdotn's answer. The following solution also handles file names with double quotes using the sed command to escape double quotes:

eval pdftk $(while IFS= read -r -d '' file; do
    echo \"$file\"
done < <(find . -maxdepth 1 -type f -print0 | \
    sed 's/"/\\"/g'| sort -zn)) cat output combinewd2.pdf



回答2:


Use -I option:

echo prefix | xargs -I % echo % post

Output:

prefix post



回答3:


It’s ugly, but you can run sh -c and access the list of arguments passed by xargs as "${@}", like so:

ls | sort -n | xargs -d'\n' sh -c 'pdftk "${@}" cat output combinewd2.pdf' "${0}"

The extra "${0}" at the end is there because, as the sh man page says

-c string

If the -c option is present, then commands are read from string. If there are arguments after the string, they are assigned to the positional parameters, starting with $0.

To test this, let’s first create some files with complicated names that will mess up most other solutions:

$ seq 1 100 | xargs -I{} touch '{} with "spaces"'
$ ls
1 with "spaces"    31 with "spaces"  54 with "spaces"  77 with "spaces"
10 with "spaces"   32 with "spaces"  55 with "spaces"  78 with "spaces"
100 with "spaces"  33 with "spaces"  56 with "spaces"  79 with "spaces"
11 with "spaces"   34 with "spaces"  57 with "spaces"  8 with "spaces"
12 with "spaces"   35 with "spaces"  58 with "spaces"  80 with "spaces"
13 with "spaces"   36 with "spaces"  59 with "spaces"  81 with "spaces"
14 with "spaces"   37 with "spaces"  6 with "spaces"   82 with "spaces"
15 with "spaces"   38 with "spaces"  60 with "spaces"  83 with "spaces"
16 with "spaces"   39 with "spaces"  61 with "spaces"  84 with "spaces"
17 with "spaces"   4 with "spaces"   62 with "spaces"  85 with "spaces"
18 with "spaces"   40 with "spaces"  63 with "spaces"  86 with "spaces"
19 with "spaces"   41 with "spaces"  64 with "spaces"  87 with "spaces"
2 with "spaces"    42 with "spaces"  65 with "spaces"  88 with "spaces"
20 with "spaces"   43 with "spaces"  66 with "spaces"  89 with "spaces"
21 with "spaces"   44 with "spaces"  67 with "spaces"  9 with "spaces"
22 with "spaces"   45 with "spaces"  68 with "spaces"  90 with "spaces"
23 with "spaces"   46 with "spaces"  69 with "spaces"  91 with "spaces"
24 with "spaces"   47 with "spaces"  7 with "spaces"   92 with "spaces"
25 with "spaces"   48 with "spaces"  70 with "spaces"  93 with "spaces"
26 with "spaces"   49 with "spaces"  71 with "spaces"  94 with "spaces"
27 with "spaces"   5 with "spaces"   72 with "spaces"  95 with "spaces"
28 with "spaces"   50 with "spaces"  73 with "spaces"  96 with "spaces"
29 with "spaces"   51 with "spaces"  74 with "spaces"  97 with "spaces"
3 with "spaces"    52 with "spaces"  75 with "spaces"  98 with "spaces"
30 with "spaces"   53 with "spaces"  76 with "spaces"  99 with "spaces"
$  ls | sort -n | xargs -d'\n' sh -c 'set -x; pdftk "${@}" cat output combinewd2.pdf' "${0}"
+ pdftk '1 with "spaces"' '2 with "spaces"' '3 with "spaces"' '4 with "spaces"' '5 with "spaces"' '6 with "spaces"' '7 with "spaces"' '8 with "spaces"' '9 with "spaces"' '10 with "spaces"' '11 with "spaces"' '12 with "spaces"' '13 with "spaces"' '14 with "spaces"' '15 with "spaces"' '16 with "spaces"' '17 with "spaces"' '18 with "spaces"' '19 with "spaces"' '20 with "spaces"' '21 with "spaces"' '22 with "spaces"' '23 with "spaces"' '24 with "spaces"' '25 with "spaces"' '26 with "spaces"' '27 with "spaces"' '28 with "spaces"' '29 with "spaces"' '30 with "spaces"' '31 with "spaces"' '32 with "spaces"' '33 with "spaces"' '34 with "spaces"' '35 with "spaces"' '36 with "spaces"' '37 with "spaces"' '38 with "spaces"' '39 with "spaces"' '40 with "spaces"' '41 with "spaces"' '42 with "spaces"' '43 with "spaces"' '44 with "spaces"' '45 with "spaces"' '46 with "spaces"' '47 with "spaces"' '48 with "spaces"' '49 with "spaces"' '50 with "spaces"' '51 with "spaces"' '52 with "spaces"' '53 with "spaces"' '54 with "spaces"' '55 with "spaces"' '56 with "spaces"' '57 with "spaces"' '58 with "spaces"' '59 with "spaces"' '60 with "spaces"' '61 with "spaces"' '62 with "spaces"' '63 with "spaces"' '64 with "spaces"' '65 with "spaces"' '66 with "spaces"' '67 with "spaces"' '68 with "spaces"' '69 with "spaces"' '70 with "spaces"' '71 with "spaces"' '72 with "spaces"' '73 with "spaces"' '74 with "spaces"' '75 with "spaces"' '76 with "spaces"' '77 with "spaces"' '78 with "spaces"' '79 with "spaces"' '80 with "spaces"' '81 with "spaces"' '82 with "spaces"' '83 with "spaces"' '84 with "spaces"' '85 with "spaces"' '86 with "spaces"' '87 with "spaces"' '88 with "spaces"' '89 with "spaces"' '90 with "spaces"' '91 with "spaces"' '92 with "spaces"' '93 with "spaces"' '94 with "spaces"' '95 with "spaces"' '96 with "spaces"' '97 with "spaces"' '98 with "spaces"' '99 with "spaces"' '100 with "spaces"' cat output combinewd2.pdf

All the arguments are quoted correctly. Note that this will fail if any filenames contain newlines, and that ls -v is basically ls | sort -n.




回答4:


This should work on filenames containing spaces, newlines, apostrophes and quotation marks (all of which are possible on UNIX filesystems):

find . -maxdepth 1 -type f -print0 |
  sort -zn |
  xargs -0 sh -c 'pdftk "$@" cat output combinewd2.pdf' "$0"

That might be overkill compared to the accepted answer, if you know you are working with simple filenames.

But if you are writing a script that will be used again in future, it is desirable that it won't explode one day when it meets unusual (but valid) inputs.

This is basically an adaptation of andrewdotn's answer which terminates input files with a zero-byte, instead of with a newline, hence preserving filenames which contain one or more newline characters.

The respective options -print0, -z and -0 tell each of the programs that input/output should be delimited by the zero-byte. Three different programs, three different arguments!




回答5:


The most intuitive way I found was to:

  • first construct the commands with -I{} and "echo",
  • then execute the commands with "bash" (as if you are executing a shell script)

Here is an example to rename extensions from ".txt" to ".txt.json":

find .|grep txt$|xargs -I{} echo "mv {} {}.json"|bash

Slightly advanced example to rename .txt to .json (removing .txt extension)

find $PWD|grep txt$|cut -d"." -f1|xargs -I{} echo "mv {}.txt {}.json"|bash

I once had a requirement to append the string "End of File" to all files.

find .|grep txt|xargs -I{} echo "echo End of File >> {}"|bash

If you do it right, xargs is the king of all commands!




回答6:


The problem here is that whilst xargs can put individual arguments in the middle of the command with -i and {}, it refuses to do this for multiple arguments. This appears to be an oversight that ends up causing us a lot of trouble!

Aside from the solutions above, another alternative is to simply add the arguments that you want to come after the files to the end of the list of files.

(
  ls | sort -n
  echo cat
  echo output
  echo combinewd2.pdf
) | xargs -d'\n' pdftk

This approach does not work on filenames containing newlines. For that rare case you should pass lines terminated with a zero byte to xargs, as offered in my other answer.




回答7:


You can do this by chaining two calls to xargs. Use the first to chain all of the args together into one string and pass that as a param to echo, and the second using -I to place that chain of args into the place where you want it, as follows:

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


来源:https://stackoverflow.com/questions/14639206/how-can-i-pass-all-arguments-with-xargs-in-middle-of-command-in-linux

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!