Linux exec command: advanced usage in shell, C and Perl

Last update: 17/12/2025
Author Isaac
  • Exec replaces the running program without changing the PID and is used in conjunction with fork() to load new executables in C and environments Unix.
  • In the shell, exec allows you to replace the shell itself or globally reconfigure file descriptors and redirections.
  • In Perl, exec and system manage the execution of commands external with different behaviors, relying on functions and modules such as Shell.
  • Mastering exec and file descriptors is key to writing robust scripts and programs, thoroughly controlling input and output.

exec command in linux

When you start working seriously with the GNU/Linux command line, sooner or later you come across the mysterious exec command and C exec functions in Unix executable programsAt first, his behavior is disconcerting: sometimes the script It "disappears" and stops executing lines; other times it's used to perform unusual file redirections or to launch remote processes. It all sounds very low-level, but that's precisely where its power lies.

In this article we're going to deconstruct that complexity. You'll see how exec can mean different things depending on whether we're talking about the shell, C, or even languages ​​like Perl.and how it fits with other basic pieces like fork(), system, file descriptors or commands such as findThe idea is that you end up with a practical and comprehensive vision, and that your hand won't tremble when you see a exec in a script or in source code.

How to create a .deb package step by step
Related article:
How to create a .deb package step by step

What is exec in Unix/Linux: general idea

In the Unix kernel, exec is the mechanism for replacing the program that is currently running. by a different one within the same process. That is: the process doesn't die and create another one, but rather its "memory image" is replaced with that of a new program. The PID remains the same, but the code and data become those of the new executable.

From a practical point of view, this means that The C exec function never returns if everything goes well.The call replaces the current program with the new one, and you will only see a return value if an error has occurred (for example, the executable does not exist or you do not have permissions).

This concept is reflected in several levels:

  • in C: family of functions exec* (execl, execv, execve, execvp, etc.).
  • In the shell (Bash, sh, etc.): internal command exec, which can replace the shell with a program or manipulate file descriptors.
  • In languages ​​like Perl: function exec which behaves similarly, with nuances compared to system.

grace is that All these uses share the same underlying idea: to stop executing what was being done and, in the same process, move on to executing something else, o modify the way that process communicates with the outside world through descriptors.

The exec family in C: replacing the process image

exec functions in C for Linux

En programming of systems with C in Linux, the The exec function family is the standard tool for loading another program into the current process.It usually appears alongside fork(), which is responsible for creating the child process.

The general definition is that exec replaces the process's memory space (code, data, stack, etc.) with that of a different program. The operating system prepares this new image and jumps to its entry point as if it had booted from scratch, but reusing the same PID.

The most common variants are:

  • int execl(const char *path, const char *arg, ...);
  • int execv(const char *path, char * const argv[]);
  • int execve(const char *path, char * const argv[], char * const envp[]);
  • int execvp(const char *file, char * const argv[]);

In all of them, path is the absolute path to the executable, except in execvpwhere you can simply pass the name and it will search in the directories defined in the environment variable PATHIf the executable is distributed as AppImage formatThe call still applies. The arguments of the new program are passed as a variable list (execl) or as an array (execv and company).

It is important to understand that These functions return -1 only if they have failed. (The new program has not yet been executed.) In the normal case, execution does not return to the point of the call, because the process code is already different.

Relationship between fork() and exec(): creating processes and executing programs

In Linux, it is customary to clearly differentiate between Two ideas: create processes and execute programsA process is not the same as an executable, although they are related.

  How to Easily Open and Analyze ETL Files in Windows

To create a new process from an existing one, you use fork()This call, simply put, makes an almost identical copy of the parent process: same code, same variable states, same open files, etc. The child receives a return value. 0 en fork()while the father receives the son's PID. If something goes wrong, both will see a -1.

This copy isn't as crude as it sounds thanks to techniques like Copy-On-Write (COW)These are used by the operating system to postpone the actual copying of memory pages until one of the processes attempts to modify them. This avoids replicating large amounts of memory only to immediately discard them if a process is later called. exec().

It is usual for the father to take care of create child processes with fork() and delegate the real work to themThe child, once created, executes exec() to load the program we're actually interested in. In this way, The father can continue creating more children or wait for one to finish. using wait(), which blocks it until the child finishes.

Putting both pieces together usually results in standards on the table:

  • The father calls fork().
  • In the child process, one of the functions is invoked. exec* with the desired program, such as ls -l.
  • The parent monitors or synchronizes the child's completion by wait().

This classic model has some inefficiencies arise when a large copy of the process is made only to immediately replace it with exec()</codeHence the importance of COW and of clearly understanding the role of each call in the process lifecycle.

The exec command in the shell: replacing the shell and playing with descriptors

Within Bash and other shells, exec It's a built-in with two great uses: replace the shell with another command and modify the configuration of the file descriptors of that shell.

The most direct case is when you use exec followed by a command. For example: uterine

exec wall "Mensaje para todos los usuarios"

Here, the shell that executes that exec ceases to exist and is replaced by the command wallEverything that comes after that line in the script will not be executed, because there is literally no shell left to interpret it.

However, the most interesting use in scripting is usually the other one: use exec with redirects to reconfigure file descriptors globally for the session or script. For example, you can have standard output go to /dev/null:

exec 1>/dev/null

Since then, Any command you type in that shell will not display anything on the screenbecause its descriptor 1 (stdout) points to /dev/nullThe powerful thing is that this affects the entire shell, not just a specific command.

You can also open an additional descriptor associated with a file:

exec 3>>/tmp/salida.log

Thus, Descriptor 3 becomes an output channel to /tmp/salida.logEverything you redirect with >&3 It will go to that file, while the rest of the standard output will remain on the screen, or wherever you have it set up.

It is important to remember that the shell maintains the position in the file associated with the descriptorIf you write multiple times, the pointer advances; if you then try to read from that descriptor, you may already be at the end of the file and get nothing. When you want to close the descriptor, simply:

exec 3>&-

This tells the shell to stop using that channel. Tricks They are very useful for structure logs in complex scripts or separate different types of output into different files without having to redirect each command individually.

Advanced example of shell exec: global redirections

In moderately elaborate scripts, it is common save the original state of the descriptors and then temporarily redirect them to dump the output to a log, a temporary file, or even to /dev/null.

A typical pattern consists of first copy the standard output to an auxiliary descriptor and then redirect the standard output to a file:

exec 3>&1
exec 1>/tmp/salida.txt

With this fragment, Descriptor 3 points to the output that descriptor 1 previously had. (The terminal (normally), and then descriptor 1 is connected to the file /tmp/salida.txtFrom then on, everything printed to stdout from the script commands will go to that file.

Later, when you no longer wish to continue recording in the file, you can restore the initial situation returning the standard output to descriptor 3 and closing the latter:

exec 1>&3
exec 3>&-

Following these lines, The commands again display their output on the screen.and the auxiliary descriptor is released. It's a clean solution for encapsulating sections of a script that need to be logged without cluttering the rest of the commands with redirects.

  Easy methods to Cease iPhone From Importing Movies to OneDrive

It is also possible redirect standard shell input to a fileso that all readings of stdin come from there, which can be useful in specific automations or in tests where you want to feed a script with pre-recorded data.

The read command and its relationship with descriptors

Within the shell ecosystem, read It is the command responsible for reading from standard input and storing the result in variablesBy default, it reads until it finds a line break, but its behavior can be fine-tuned with several options.

the easiest way is

read MIVAR

With this, The string you type on the keyboard until you press Enter is saved in MIVARIt's quite common to add the option -r so that backslashes are not interpreted as escape characters:

read -r MIVAR

There are particularly useful options such as -pwhich allows you to display a prompt text, and -swhich prevents what you type from echoing on the screenThat's exactly what you use when you want to request a password within a script:

read -s -p "Contraseña: " PASSWD

In this case, You won't see the characters you type, just like when you run su o sudo. Also read It is closely connected to the special variable. IFS, which defines which characters are considered field separators (by default tab, space and line break).

If you do something like:

IFS="-"; read A B C

The order will interpret the hyphen character as a separatorDistributing the read fields among variables A, B, and C. If there are more variables than fields, the latter will be empty; if there are more fields than variables, The last one will accumulate all the remaining ones..

And of course, All of this is combined with the redirects you configure with exec: if you have redirected stdin to a file, read It will retrieve its data from there instead of the keyboard. That flexibility is one of the cornerstones of well-designed shell scripts.

exec in Perl: differences with system and advanced usage

In Perl, the concept of exec It is very much in line with the behavior in C and in the shell.This is used to replace the current process with another program. However, Perl also offers system, which is often confused with exec even if they don't do the same thing.

The function system It launches an external command and waits for it to finish, returning control to the script.. Instead, exec It completely replaces the Perl process with the program called and does not return to the scriptexcept in case of error. A very basic example would be:

exec 'cat -n /etc/passwd';
die "no se pudo ejecutar cat: $!";

Si the call to exec If it succeeds, it will never be executed. diebecause the Perl interpreter will have been replaced by the binary catIf it fails (for example, because it doesn't exist) cat), then it is executed die displaying the error message and the value of $!.

One very useful detail is that, just like with system, you can summon exec with a list of arguments to prevent shell metacharacters from being interpreted. For example: uterine

exec '/bin/echo', 'Los argumentos son: ', @ARGV;

If you run that script like this:

./exec.pl 'uno' '| ls ' '| who > quien'

You will see that the arguments that include | or redirects do not activate the shellbut they are transferred as is to /bin/echoThe output would be something like this:

Los argumentos son: uno | ls  | who > quien

That is to say, no command has actually been executed, only the texts have been shown.

Use exec in Perl to prepare a runtime environment

Beyond simple examples, Perl lends itself to building scripts that sophisticatedly prepare the working environment before running another programA typical case is when you are going to launch tasks on remote machines via SSH and you want to recreate a certain context of the local process.

A common approach is to have a subroutine that dynamically builds a temporary script and then executes itIn that script, you can set the working directory, environment variables, or the behavior of the signals, and finally use system o exec depending on whether we want to return to the packaging or not.

  A guide to creating website shortcuts in Windows 11 in a few steps

For example, it can be stored in a multi-line chain a small program that:

  • Change to the original directory from which the main script was invoked.
  • Restore environment variables from a serialized list.
  • Execute the actual command to system, checking its exit status.
  • Delete the temporary script and ends explicitly with exit(0).

Before saving that program to the temporary file, Text markers are replaced (the directory, the command to execute, the script name, etc.) with their actual values. With this technique, you can encapsulate all the environment preparation logic and have a single entry point that simply "wraps" any remote execution.

This type of solution takes full advantage of Perl's ability to manipulate strings, files, and processesand it fits very well with the functions exec y system when very specific behaviors are needed in distributed systems.

Perl's Shell module and implicit command calling

Another curious aspect related to The execution of external commands in Perl is the module ShellThis module allows you to call system programs as if they were Perl functions, thanks to the use of AUTOLOAD.

Imagine you load the module like this:

use Shell qw(echo cat ps cp);

From that moment, when you write something like:

$foo = echo("howdy", "funny", "world");

What happens underneath is that Perl cannot find a subroutine called echo and shoots AUTOLOAD of the moduleThis mechanism:

  • Identify the command name starting from the full name of the subroutine (Shell::echo).
  • Dynamically construct a real function that will execute that system command.
  • Forward the call to the new feature, passing on the arguments received.

If you inspect the execution with the Perl debugger, you'll see how The arguments are organized into @_ and the command to be launched is constructed.The result of running echo It is collected and stored in $foo, so that:

print $foo;

It will show something of the style howdy funny world with the format that it generates echo of the systemThis approach is convenient, but it should not be overused because it can make code readability and error handling more difficult.

The exec command in shell as an advanced redirection tool

As we have seen, the command exec In the shell, it's not just used to replace the shell.Instead, it's frequently used to open, close, or duplicate file descriptors. This capability allows for the creation of very powerful patterns in scripts.

For example, you might want permanently redirect the output of the entire script to a log file without having to >>log.txt on each line. Something like:

exec >/var/log/mi_script.log 2>&1

With this, Both standard output and error output will go to the same file From the beginning of the script. From then on, any command that fails will leave a trace in the log without cluttering the terminal.

In other cases, you might be interested in associate specific descriptors to temporary files to save data that you will process later. By closing those descriptors with exec n>&-You free up resources and prevent leaks of handlers.

It is true that this type of construction is not seen in basic scripts, but When you start writing, serious administrative utilities become almost indispensable. to properly control what is displayed on the screen, what is saved, and how the information is structured.

In short, to master exec as an advanced redirection tool gives you a level of control over shell scripting I/O which makes the difference between "homemade" scripts and robust production tools.

At the end of this whole journey, the key idea is that exec, whether in C, the shell, or Perl, always revolves around two axes: replacing the running program and accurately managing inputs and outputs.Understanding how they combine with fork(), system, read or modules like Shell It allows you to design cleaner, more efficient, and more secure solutions, whether it's for launching remote processes, encapsulating complex execution environments, or simply writing scripts that do exactly what you want, without surprises.