`xargs` is a really great GNU utility that reads items from standard input and executes a command a certain number of times using the blank delimited input as final arguments.
Many times you can achieve the same result by using `find -exec`, but there is one thing that I really like about `xargs`: concurrency via the --max-procs option.
I will provide a few basic `xargs` examples, and I will then conclude with an example of using the --max-procs option.
Pass the first field of the first ten lines of '/etc/passwd' (user ID's) as arguments to the `id` command (-I causes newline to become separator):
$ cut -f1 -d: < /etc/passwd | head -10 | xargs -I '{}' id '{}'
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel) context=user_u:system_r:unconfined_t
uid=1(bin) gid=1(bin) groups=1(bin),2(daemon),3(sys) context=user_u:system_r:unconfined_t
uid=2(daemon) gid=2(daemon) groups=1(bin),2(daemon),4(adm),7(lp) context=user_u:system_r:unconfined_t
uid=3(adm) gid=4(adm) groups=3(sys),4(adm) context=user_u:system_r:unconfined_t
uid=4(lp) gid=7(lp) groups=7(lp) context=user_u:system_r:unconfined_t
uid=5(sync) gid=0(root) groups=0(root) context=user_u:system_r:unconfined_t
uid=6(shutdown) gid=0(root) groups=0(root) context=user_u:system_r:unconfined_t
uid=7(halt) gid=0(root) groups=0(root) context=user_u:system_r:unconfined_t
uid=8(mail) gid=12(mail) groups=12(mail) context=user_u:system_r:unconfined_t
uid=9(news) gid=13(news) groups=13(news) context=user_u:system_r:unconfined_t
Pass each line of the output of `pgrep ssh` to `ps` as command-line arguments:
$ pgrep ssh
3312
17036
21839
26978
27535
27538
31416
31419
31833
31837
32539
32542
$ pgrep ssh | xargs ps
PID TTY STAT TIME COMMAND
3312 ? Ss 0:00 /usr/sbin/sshd
17036 ? Ss 0:00 /usr/bin/ssh-agent /usr/bin/dbus-launch --exit-with-session /etc/X11/xinit/Xclients
21839 pts/7 S+ 0:00 ssh steve@saturn01
26978 pts/8 S+ 0:00 ssh steve@venus01
27535 ? Ss 0:00 sshd: steve [priv]
27538 ? S 0:02 sshd: steve@pts/8
31416 ? Ss 0:01 sshd: steve [priv]
31419 ? S 1:00 sshd: steve@pts/14
31833 ? Ss 0:01 sshd: steve [priv]
31837 ? S 0:02 sshd: steve@pts/15
32539 ? Ss 0:04 sshd: steve [priv]
32542 ? S 0:14 sshd: steve@pts/12
Here is an example of how you could use either `xargs` or `find -exec` to achieve the same result:
find -type f | xargs md5sum
d41d8cd98f00b204e9800998ecf8427e ./test_file3
d41d8cd98f00b204e9800998ecf8427e ./test_file1
d41d8cd98f00b204e9800998ecf8427e ./test_file2
d41d8cd98f00b204e9800998ecf8427e ./test_file4
find -type f -exec md5sum '{}' \;
d41d8cd98f00b204e9800998ecf8427e ./test_file3
d41d8cd98f00b204e9800998ecf8427e ./test_file1
d41d8cd98f00b204e9800998ecf8427e ./test_file2
d41d8cd98f00b204e9800998ecf8427e ./test_file4
Finally, the example we have all been waiting for. One of the things I really like about `xargs` is the ability to define how many processes can be invoked concurrently while executing built command lines from the standard input. The default maximum processes with `xargs`
Here is an example of using `xargs` to allow
four concurrent processes to execute at a time, but no more:
$ find -type f | xargs --max-procs=4 -I '{}' -i sh -c "echo '{}' ; sleep 5"
./test_file10
./test_file8
./test_file3
./test_file12
<~5 second delay for each>
./test_file1
./test_file6
./test_file13
./test_file11
<~5 second delay for each>
./test_file7
./test_file2
./test_file14
./test_file5
Here is the output of the process table at 5 second intervals for the previous example:
$ ps -f
UID PID PPID C STIME TTY TIME CMD
steve 1078 12879 0 14:48 pts/10 00:00:00 xargs --max-procs=4 -I {} -i sh -c echo '{}' ; sleep 5
steve 1079 1078 0 14:48 pts/10 00:00:00 sh -c echo './test_file10' ; sleep 5
steve 1080 1079 0 14:48 pts/10 00:00:00 sleep 5
steve 1081 1078 0 14:48 pts/10 00:00:00 sh -c echo './test_file8' ; sleep 5
steve 1082 1078 0 14:48 pts/10 00:00:00 sh -c echo './test_file3' ; sleep 5
steve 1083 1078 0 14:48 pts/10 00:00:00 sh -c echo './test_file12' ; sleep 5
steve 1084 1083 0 14:48 pts/10 00:00:00 sleep 5
steve 1085 1082 0 14:48 pts/10 00:00:00 sleep 5
steve 1086 1081 0 14:48 pts/10 00:00:00 sleep 5
steve 1087 12879 0 14:48 pts/10 00:00:00 ps -f
steve 12876 29766 0 09:41 pts/10 00:00:00 su -
steve 12879 12876 0 09:41 pts/10 00:00:00 -bash
$ ps -f
UID PID PPID C STIME TTY TIME CMD
steve 1078 12879 0 14:48 pts/10 00:00:00 xargs --max-procs=4 -I {} -i sh -c echo '{}' ; sleep 5
steve 1090 1078 0 14:48 pts/10 00:00:00 sh -c echo './test_file1' ; sleep 5
steve 1091 1078 0 14:48 pts/10 00:00:00 sh -c echo './test_file6' ; sleep 5
steve 1092 1078 0 14:48 pts/10 00:00:00 sh -c echo './test_file13' ; sleep 5
steve 1093 1090 0 14:48 pts/10 00:00:00 sleep 5
steve 1094 1091 0 14:48 pts/10 00:00:00 sleep 5
steve 1095 1092 0 14:48 pts/10 00:00:00 sleep 5
steve 1096 1078 0 14:48 pts/10 00:00:00 sh -c echo './test_file11' ; sleep 5
steve 1097 1096 0 14:48 pts/10 00:00:00 sleep 5
steve 1100 12879 0 14:48 pts/10 00:00:00 ps -f
steve 12876 29766 0 09:41 pts/10 00:00:00 su -
steve 12879 12876 0 09:41 pts/10 00:00:00 -bash
$ ps -f
UID PID PPID C STIME TTY TIME CMD
steve 1078 12879 0 14:48 pts/10 00:00:00 xargs --max-procs=4 -I {} -i sh -c echo '{}' ; sleep 5
steve 1102 1078 0 14:48 pts/10 00:00:00 sh -c echo './test_file7' ; sleep 5
steve 1103 1102 0 14:48 pts/10 00:00:00 sleep 5
steve 1104 1078 0 14:48 pts/10 00:00:00 sh -c echo './test_file2' ; sleep 5
steve 1105 1078 0 14:48 pts/10 00:00:00 sh -c echo './test_file14' ; sleep 5
steve 1106 1078 0 14:48 pts/10 00:00:00 sh -c echo './test_file5' ; sleep 5
steve 1107 1104 0 14:48 pts/10 00:00:00 sleep 5
steve 1108 1105 0 14:48 pts/10 00:00:00 sleep 5
steve 1109 1106 0 14:48 pts/10 00:00:00 sleep 5
steve 1112 12879 0 14:48 pts/10 00:00:00 ps -f
steve 12876 29766 0 09:41 pts/10 00:00:00 su -
steve 12879 12876 0 09:41 pts/10 00:00:00 -bash
Hopefully you have found this post useful, and it has perhaps shown you one of the less frequently known perks of using `xargs`.