Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Many simple commands using xargs could be rewritten as commands using subshells. For instance, here is something I was using earlier today, to concatenate the ten largest binaries in /usr/bin, written using a subshell vs xargs:

subshell:

$ cat $(du -sh /usr/bin/* | sort -h | tail | cut -d "      " -f 2 | tr "\n" " ")

xargs:

$ du -sh /usr/bin/* | sort -h | tail | cut -d "      " -f 2 | tr "\n" " " | xargs cat

So when should you use a subshell and when should you use xargs?

NOTE:

The delimiter for cut is a hard tab, which apparently doesn't display properly on SE.

share|improve this question

1 Answer 1

up vote 4 down vote accepted

This is a slightly opinionated question but I'll just say this, it's highly dependent on 2 things:

  1. What is the command you're going to run?
  2. How many instances you're going to run?

If you're likely to run dozens to 100's of the same process, then xargs makes the most sense. Also if the processes are going to be expensive to start up, xargs is likely the best route to go.

If however there will only be a handful of instances of the command, then running them in a subshell is fine.

If the length of the arguments produced by the subshell will be extremely long, then you'd want to use xargs. But this limit is pretty extreme, typically 2MB-4MB of characters, so it's unlikely that you'd exceed it. You can check like this:

$ xargs --show-limits < /dev/null
Your environment variables take up 4805 bytes
POSIX upper limit on argument length (this system): 2090299
POSIX smallest allowable upper limit on argument length (all systems): 4096
Maximum length of command we could actually use: 2085494
Size of command buffer we are actually using: 131072

By the way, neither of these commands appear to work. The cut -d " " -f2 is not valid, cut can only take a single character as the delimiter. Try this instead:

$ du -sh /usr/bin/* | sort -h | awk 'NR<=10 {print $2}' | tr "\n" " "
-or-
$ du -sh /usr/bin/* | sort -h | tail | cut -f2- | tr "\n" " "

Using awk here will likely cause you issues if you have any filenames or directories with spaces, so use it with caution.

$ ll
total 0
-rw-rw-r--. 1 saml saml 0 Feb 22 19:47 file 1
-rw-rw-r--. 1 saml saml 0 Feb 22 19:47 file 2

$ du -sh * | sort -h | awk 'NR<=10 {print $2}' | tr "\n" " "
file file $

I'd use the cut -f2- method, but that's just me, others' might give you a more sophisticated awk solution, but use what makes the most sense to you.

Using awk + cat

NOTE: When piping output to xargs there is no need to call cat, xargs will automatically echo the output it's passed, by default.

$ du -sh * | sort -h | tail | cut -f2- | tr "\n" " " | xargs
file 1 file 10 file 2 file 3 file 4 file 5 file 6 file 7 file 8 file 9

EDIT #1

If you're using tabs to delimit with cut you don't need to do so explicitly, it defaults to that.

   -d, --delimiter=DELIM
          use DELIM instead of TAB for field delimiter
share|improve this answer
    
The cut is valid (I used it earlier), it just seems to be that SE doesn't display hard tabs. –  haneefmubarak Feb 23 at 1:00
    
@haneefmubarak - it displays as 8 spaces. –  slm Feb 23 at 1:03
    
*it just seems to be that SE likes to soften hard tabs... –  haneefmubarak Feb 23 at 1:05
    
But the tab delimit is noted. Thanks for that. –  haneefmubarak Feb 23 at 1:06
1  
@haneefmubarak - yeah I figured you tried them so it seemed odd. I've never tried pasting hard tabs, so you taught me something as well 8-). –  slm Feb 23 at 1:09

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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