Wednesday, January 10, 2018

8 Practical Examples of Linux Xargs Command for Beginners

https://www.howtoforge.com/tutorial/linux-xargs-command

The Linux xargs command may not be a hugely popular command line tool, but this doesn't take away the fact that it's extremely useful, especially when combined with other commands like find and grep. If you are new to xargs, and want to understand its usage, you'll be glad to know that's exactly what we'll be doing here.
Before we proceed, please keep in mind that all the examples presented in this tutorial have been tested on Ubuntu 14.04 LTS. Shell used is Bash, and version is 4.3.11.

1. How Xargs command works?

Well, before jumping onto its usage, it's important to understand what exactly Xargs does. In layman's terms, the tool - in its most basic form - reads data from standard input (stdin) and executes the command (supplied to it as argument) one or more times based on the input read. Any blanks and spaces in input are treated as delimiters, while blank lines are ignored.
If no command is supplied as argument to xargs, the default command that the tool executes is echo. For example, in the following example, I just executed 'xargs' and entered 'Hello World' on stdin. As I pressed Ctrl+D (to tell xargs that we're done with the input), the echo command was automatically executed, and 'Hello World' was printed again.
How xargs command works

2. How to use xargs with another command?

While echo is the default command xargs executes, you can explicitly specify any other command. For example, you can pass the find command along with its '-name' option as argument to xargs, and then pass the name of the file (or type of files) you want find to search as input through stdin.
Here's the complete command in question:
xargs find -name
For example, we provided "*.txt" in input through stdin, which means we want the find command to search all .txt files in the current directory (as well as its subdirectories).
Here's the command in action:
Combine xargs with other commands

3. How to make xargs execute command multiple times (once for each input line/argument)

In the example we discussed in the previous section, we wanted to search for .txt files, so we provided "*.txt" in the input. But what if the requirement is to also search for other types of files as well, like .log and .tmp?
Try giving these as input to xargs after "*.txt" and see what happens. Well, you should get an error similar to the following:
Execute xargs multiple times
That's because xargs passes "*.txt" and "*.log" as file name input to the find command and then find fails as it runs with two file names in input. You can think of the find command running in the following way:
find -name "*.txt" "*.log"
And it's is not the correct way.
What we want is that the xargs command should first pass "*.txt" to the find command, so that find gives us results related to .txt files, and then "*.log" is passed. This can be done using the -L command line option xargs provides.
The -L command line option requires a number which it treats as the maximum number of non-blank lines that should be passed as input to the command in one time. So, in our case, that value will be 1, as we want one input line to passed as input to find at one time.
So, here's the command that we should run:
xargs -L 1 find -name
The following screenshot shows the aforementioned command in action:
xargs input / output
So far, so good. But what if you pass the input in the following way:
"*.txt" "*.log"
Well, the command will fail because '-L 1' will make sure the complete line is passed to the find command.
Xargs -L flag
In situations like these, you can use the '-n' command line option.
The '-n' command line option, like '-L', requires a number that would represent the number of arguments you want xargs to pass per command line. In the case we just discussed, "*.txt" and "*.log" should be different arguments, and since we want them to be passed individually, we'll have to provide '1' as value to '-n'.
 xargs -n 1 find -name
Xargs -n switch
So these are the ways in which we can make xargs execute a command multiple times.

4. How to make xargs handle filenames with spaces

If you recall, in the beginning, we mentioned that xargs treats blank spaces (as well as newline characters) as delimiters. This may cause issues in cases where-in the filenames being passed as input to xargs contain spaces.
For example, suppose the current directory contains a file named 'new music.mp3', and you want xargs to pass this name to mplayer so that the latter can play the file. If you go by the conventional way, you'll get an error:
Xargs handle spaces in file names
That's because due to the space between 'new' and 'music.mp3', these are treated as two different files by mplayer. One way to solve this problem is to use backslash while providing the input:
new\ music.mp3
The other way is to change the delimiter, which you can do using the -d option. For example, you can ask xargs to only consider newline as a delimiter, something which can be done in the following way:
xargs -d '\n' mplayer
xargs -d switch

5. How to make xargs handle filenames with newline characters

So, now we know how we can make xargs handle filenames that contain white spaces. But what about newlines? Yes, filenames can have newline characters as well. For example, there's a file named 'foo'[newline]'file.txt'. On terminal, the name is displayed as 'foo?file.txt'.
Xargs handle newline character
Now, suppose, I want the find command to find all files with names starting with text 'foo', and then use xargs to open these files in gedit. Here's the command:
find . -name "foo*" | xargs gedit
Sadly, the command fails to achieve its purpose as a new file with name 'foo' opens in Gedit. That's likely because the newline character is treated as a delimiter by xargs.
To sort this problem out, use the -print0 option that find offers and couple it with xarg's -0 option. Here's how the man page of find explains this option:
 -print0
True; print the full file name on the standard output, followed by a null character (instead of thenewline character that -print uses). This allows file names that contain newlines or other types ofwhite space to be correctly interpreted by programs that process the find output. This option corresponds to the -0 option of xargs.
So, here's the command we should be using:
find . -name "foo*" -print0 | xargs -0 gedit

6. How to find files containing a specific text

The xargs command comes in really handy if you want to search for files containing a specific text/string. For example, if you want to find .txt files containing text 'abc', then this can be done in the following way:
find -name "*.txt" | xargs grep "abc"
Here's the command in action:
Xargs and grep
As is quite obvious, in this case, the xargs command gets its input from the find command.

7. How to make xargs accept input from a file 

So far, we have seen xargs accepting input from stdin (which is the default behavior) as well as from another command (discussed in last section). However, if you want, you can also have xargs accept input from a file.
The command's -a option lets you do this. This option expects a filename - this would be the file from which xargs will be reading input.
For example, suppose there's a file with name 'input.txt'. It contains the input for xargs (basically, the contents are two filenames: testfile1.txt and testfile2.txt). Here's how xargs can be used to read input from this file, and pass it to another command, say ls.
xargs -a input.txt ls -lart
Here's the command in action:
Xargs file input

8. How to make xargs seek user permission before executing a command

We have already discussed how you can make xargs execute a command multiple times (see point 3 above). But what if you want xargs to ask for your permission each time it runs the command? Is that possible? Yes, it is - the -p command line option makes it possible.
Here's an example of how you can run xargs in interactive mode:
Xargs request permission from user

Conclusion

We've just scratched the surface here as there are plenty of other features the xargs command provides in the form of command line options. Do try the xargs concepts/features we've explained in this tutorial, and in case of any doubt or query, go through its man page.

No comments:

Post a Comment