I need to understand this command line:

file=`echo $1 | xargs -n 1 basename | cut -d '.' -f1`

4 Answers 4


It assigns a bit of a filename (possibly with a path) to the variable file. Specifically, the bit before the first . character in the filename of the file itself. In other words, it takes something like /some/path/hello.world and parses out the hello bit.

A tip would be to run each part of the pipeline on the command line:

$ thing="/some/path/hello.world"

$ echo "$thing"

$ echo "$thing" | xargs -n 1 basename

$ echo "$thing" | xargs -n 1 basename | cut -d '.' -f 1

The backticks are used to for returning the output of the pipeline and assigning it to file. The $1 is the first argument on the command line (for whatever script or shell function this is part of).

It is likely that the only reason xargs -n 1 basename is used instead of plain basename is that the basename utility doesn't read from standard input, but xargs does.

A shorter (and faster) version of the same thing in bash or ksh93 would be

  • Maybe also explain the possible consequences of failing to quote the echo argument properly (the string will be split into tokens and wildcards will be expanded, basically).
    – tripleee
    Apr 13, 2017 at 18:58

The line extracts the filenames without extensions from paths provided via $1 (the first argument to the script in which that line appears). The result is saved in the variable file.


$ echo /etc/dhcpcd.conf ../foo/bar/filename.tar.gz | xargs -n 1 basename | cut -d '.' -f1

The combination of echo and xargs is rather curious here.

basename takes a pathname on the command line, and outputs the final component of it (i.e. part after the last slash, usually). xargs just places words read from its input (the pipe) to the command line of basename here. So why not just use basename $1?

There is, however, a difference.

In echo $1 | xargs -n 1 basename if the parameter $1 contains whitespace, xargs will split it on spaces, and call basename for each word separately. The end result will be that a part of the filename will be picked for all the words, as Arminius showed.

The other option, basename $1, would call basename only once (and fail in some nice ways due to word splitting.)

If the command is supposed to only handle one filename, it would be better written as:

file=$(basename "$1" | cut -d '.' -f 1)

With the quotes. (or using the suffix-stripping shell expansion ${file%%.*} instead of the cut as Kusalananda showed.)

If, on the other hand, it's supposed to handle multiple file names, it might be cleaner to pass them using an array, or in the positional parameters (all of them, not just $1).


The line stores the name of a file, without extension and path, in the variable $file.

In detail:

echo $1 prints the first command line argument passed to the script, xargs -n 1 basename passes the echoed string as arguments to the command basename, which strips the path from the filename. cut -d '.' -f1 removes the extension.

So, for example if you execute

echo directory/test.sh | xargs -n 1 basename | cut -d '.' -f1

the result (saved to $file) will be test.


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