---
name: "xe"
section: "1"
platform: "linux"
package: "xe"
version: "0.11-5"
release: "Debian 13 (Trixie)"
platforms: ["linux"]
url: "https://new.carta.tech/xe"
---

# xe(1)

execute a command for every argument

## NAME

**xe** – execute a command for every argument

## SYNOPSIS

**xe** \[**-0FLRnqv**\] \[**-I** *replace-arg*\] \[**-N** *maxargs*\] \[**-j** *maxjobs*\] *command ...*

**xe** \[*flags ...*\] **-p** *pattern* *command ...* \[**+** *pattern* *command ...*\]...

**xe** \[*flags ...*\] **-f** *argfile* *command ...*

**xe** \[*flags ...*\] **-s** *shellscript*

**xe** \[*flags ...*\] **-a** *command ...* **--** *args ...*

**xe** \[*flags ...*\] **-A** *argsep* *command ...* *argsep* *args ...*

## DESCRIPTION

The **xe** utility constructs command lines from specified arguments, combining some of the best features of [xargs(1)](/xargs/1.md) and [apply(1)](/apply/1.md).

**xe** means “execute for every ...”.

**xe** supports different methods to specify arguments to commands:

- *command ...*

  By default, arguments - separated by newlines - are read from the standard input. The resulting command is constructed from the command line parameters, replacing *replace-arg* with the read argument, and is executed with [execvp(3)](/execvp/3.md).

  In this mode, no shell is involved and *replace-arg* must appear as a word on its own, i.e. ‘foo {} bar’ will work, but ‘foo{} bar’ will not, where {} is the default value for *replace-arg*.

  If no argument is specified, the default is ‘**printf** **%s\\n**’.

- **-f** *argfile*

  Read arguments from *argfile*, instead of the standard input.

  This does not close the standard input for execution, it is passed to the forked process.

- **-s** *shellscript*

  In this mode, the single parameter *shellscript* is executed using **sh** **-c**. In the script, the specified arguments can be accessed using $1, $2, ...

  For example:

  ```
  echo 'a\nb' | xe -N2 -s 'echo $2 $1'
  ```

- **-a** *command ...* **--** *args ...*

  In this mode, everything after **--** is passed as *args* to *command*.

- **-A** *argsep* *command ...* *argsep* *args ...*

  Same as **-a**, but the custom argument separator *argsep* is used to distinguish between *command* and its *args*.

The options are as follows:

- **-0**

  Input filenames are separated by NUL bytes (instead of newlines, which is the default)

- **-F**

  Fatal: stop and exit when a command execution fails.

- **-L**

  Run the resulting commands with line-buffered output; lines from two jobs will not interleave. When used twice, or with **-vv**, also prefix each line with the number of the job (see ENVIRONMENT) in such a manner that the output can be piped to ‘sort -snk1’ to group it.

- **-R**

  Return with status 122 when no arguments have been specified (instead of 0, the default). **xe** never executes a command when no arguments are specified.

- **-n**

  Dry run: don't run the resulting commands, just print them.

- **-q**

  Quiet mode: redirect standard output and standard error of commands to /dev/null.

- **-v**

  Verbose: print commands to standard error before running them. When used twice, also print job id and exit status for each command.

- **-p**

  Enable[make(1)](/make/1.md)- style percent rules. The first argument of *command ...* is regarded as a pattern, see PERCENT RULES below. Patterns without a slash (or ‘\*\*’) are matched against the basenames only.

  Multiple runs of patterns and commands are separated by ‘+’. Only the first matching percent rule is executed; in case no pattern matches, no command is run.

- **-I** *replace-arg*

  Replace first occurrence of *replace-arg* (default: **{}**) in the resulting command with the argument(s). Pass an empty *replace-arg* to disable the replace function. Contrary to [xargs(1)](/xargs/1.md) this will expand into multiple arguments when needed.

- **-N** *maxargs*

  Pass up to *maxargs* arguments to each command (default: 1).\
   Using **-N0** will pass as many arguments as possible.

- **-j** *maxjobs*

  Run up to *maxjobs* processes concurrently. Using **-j0** will run as many processes as there are CPU cores running. If *maxjobs* ends with an ‘**x**’, it is regarded as a multiplier of the number of running CPU cores (rounded down, but using at least one core).

## PERCENT RULES

The percent rules of **xe** are similar to the globs of [sh(1)](/sh/1.md) or [fnmatch(3)](/fnmatch/3.md): ‘?’ matches a single character that is not ‘/’. ‘/’ matches one or multiple ‘/’ in the string. ‘\*’ matches zero or more characters, but never ‘/’. ‘\*\*’ matches zero or more characters, including ‘/’. Note that all of these also match leading dots in file names.

‘{*a*,*b*,*c*}’ matches either *a*, *b* or *c*. ‘\[*abc*\]’ matches one of the characters *abc* (but never ‘/’). ‘\[!*abc*\]’ matches all characters but *abc*. Alternatively, ‘\[^*abc*\]’ can be used too. ‘\[*a*-*c*\]’ matches any character in the range between *a* and *c* inclusive. In character ranges, characters can be escaped using a backslash.

In the pattern, a single occurrence of ‘%’ matches one or more characters, and replaces the first occurrence of ‘%’ with the matched string in the remaining arguments, which are then used as the command to be executed.

## ENVIRONMENT

The environment variable ITER is passed to the child process and incremented on each command execution.

## EXIT STATUS

**xe** follows the convention of GNU and OpenBSD xargs:

- 0

  on success

- 123

  if any invocation of the command exited with status 1 to 125.

- 124

  if the command exited with status 255

- 125

  if the command was killed by a signal

- 126

  if the command cannot be run

- 127

  if the command was not found

- 1

  if some other error occurred

Additionally, 122 is returned when **-R** was passed and the command was never executed.

## EXAMPLES

Compress all .c files in the current directory, using all CPU cores:

```
xe -a -j0 gzip -- *.c
```

Remove all empty files, using [lr(1)](/lr/1.md):

```
lr -U -t 'size == 0' | xe -N0 rm
```

Convert .mp3 to .ogg, using all CPU cores:

```
xe -a -j0 -s 'ffmpeg -i "${1}" "${1%.mp3}.ogg"' -- *.mp3
```

Same, using percent rules:

```
xe -a -j0 -p %.mp3 ffmpeg -i %.mp3 %.ogg -- *.mp3
```

Similar, but hiding output of ffmpeg, instead showing spawned jobs:

```
xe -ap -j0 -vvq '%.{m4a,ogg,opus}' ffmpeg -y -i {} out/%.mp3 -- *
```

## SEE ALSO

[apply(1)](/apply/1.md), [parallel(1)](/parallel/1.md), xapply(1), [xargs(1)](/xargs/1.md)

## AUTHORS

Leah Neukirchen ⟨*leah@vuxu.org*⟩

## LICENSE

**xe** is in the public domain.

To the extent possible under law, the creator of this work has waived all copyright and related or neighboring rights to this work.

**http://creativecommons.org/publicdomain/zero/1.0/**
