You are not logged in.
So as I'm getting a bit deeper into scripting, I'm starting to take a look at other people's shell scripts, pick and pull them apart and try to reason the logic behind things... The exec command, without a doubt is the most infuriating commands. I (think) I get *how* it works, but I'm still trying to understand *why*. So if anyone has the time, or patience, to read through this, and explain, I'd appreciate it.
So the way I have seen it demonstrated and explained is that the exec() command can work into two methods, that are completely unrelated. The first way is that it can run (execute) a command or process, but replace the current process with the newly run one. So if you run
$ exec ls /home/kingghidorah
from a bash terminal, the ls command takes the PID of the command that exec is being called from. In this case, if you call it from the Terminal, it assigns the ls command the same PID that the bash terminal is using, then runs the ls command, then naturally, ls ends, knocking out the bash terminal in the process. Because the terminal "became" the ls command, and ls ended, the terminal we're using either exits or we're booted out of that user.
Of course this is not the 'normal' behavior of the shell. If we run ls without invoking exec before it, ls would run as a 'child' process, do it's lssy business, and return command and control back to the terminal, thus returning control to the user.
1. So, running this directly from the terminal..doesn't strike me as too useful.(if I'm wrong, please do give me some use cases). A proper use case of this, 'no Process Forking' would be more for scripting purposes.
If you initiate a script, called First.sh, and inside First.sh you need to run a bunch of commands, as well as call another script, this one called Second.sh.
Kingghidorah$ cat First.sh
#!/bin/bash
commands...
commands...
commands...
exec Second.sh
Kingghidorah$ cat Second.sh
#!/bin/bash
commands...
commands...
commands...
Kingghidorah$
2. So given the above... if we were to run First.sh WITHOUT the exec command from the termie, with ./First.sh, it would run through the commands, and runs Second.sh... but once Second.sh finished it's own list of commands, Second.sh exits and the prior bash shell is returned to the user. What is the point of having the exec in front of Second.sh then?
I turn to a real life example below...
#!/bin/sh
# /etc/X11/xinit/xinitrc #
# global xinitrc file, used by all X sessions started by xinit (startx)
# invoke global X session script
exec /etc/X11/Xsession
This is the xinitrc script(obviously...) this script is called by startx.
3. I have seen people's personal ~/.xinitrc scripts as well that usually end with the the starting of the session using exec. Why this is? If this script was run without the the exec, wouldn't this script close anyway?
What the exec does is start /etc/X11/Xsession, in place of the current xinitrc script. So effectively, it "turns" the PID of /etc/X11/xinit/xinitrc into the process Xsession. I'm not seeing the value here... Because it's the last line of code in the script, it was literally about to exit anyway right? So explicitly saying to replace xinitrc with Xsession seems needless, or am I missing something?
I have another post of explanation/questions regarding exec with redirection which i"ll post shortly...
Any help here would be appreciated, as well as some examples of how putting exec in a script is needed.
Last edited by Horizon_Brave (2016-02-01 18:43:47)
"I have not failed, I have found 10,000 ways that will not work" -Edison
Offline
exec is also useful for working with file descriptors. It opens or closes them. See e.g. here for examples.
Yea I was going to make a second post on it, cause I have a few questions in regards to that as well...
Do you know anything about the questions I posed in my post?
"I have not failed, I have found 10,000 ways that will not work" -Edison
Offline
I'm rubbish with scripting so I will have to leave your other questions but I can answer this:
3. I have seen people's personal ~/.xinitrc scripts as well that usually end with the the starting of the session using exec. Why this is? If this script was run without the the exec, wouldn't this script close anyway?
exec() is usually used to start the window manager and it is used so that when the window manager is closed (ie, the user quits the x session) then the system returns to the login screen.
If exec() was not used then quitting the window manager would return the user to the console screen but still logged in.
Usually, the former set up is preferred (but not always).
Offline
Kingghidorah$ cat First.sh
#!/bin/bash
commands...
commands...
commands...exec Second.sh
Kingghidorah$ cat Second.sh
#!/bin/bash
commands...
commands...
commands...Kingghidora
Makes no sense doing this.
What you are doing with the 'exec' in this case is replacing the bash command interpreter by ... the bash command interpreter.
Offline
Makes no sense doing this.
What you are doing with the 'exec' in this case is replacing the bash command interpreter by ... the bash command interpreter.
Xaos, Right, that's what I thought.
HoaS, Okay, I suppose that makes sense but is it really that bad to have the user still logged in? In fact wouldn't that be convenient? Is it more of a security thing?
I can't think of a real reason to use it in a script. Is it really that bad to have the person return to the shell after the script runs?
Also generally you can only have 1 working exec command in a script right? Since once it's run, it basically kills the current script, so everything below that 1st exec isn't run.
"I have not failed, I have found 10,000 ways that will not work" -Edison
Offline
....
I can't think of a real reason to use it in a script. ....
Wrapper scripts commonly use `exec`
Be Excellent to Each Other...
The Bunsenlabs Lithium Desktop » Here
FORUM RULES and posting guidelines «» Help page for forum post formatting
Artwork on DeviantArt «» BunsenLabs on DeviantArt
Offline
HoaS, Okay, I suppose that makes sense but is it really that bad to have the user still logged in?
No, not at all.
It's simply a matter of preference -- usually, logging out of the x session would mean that the user has finished using the computer so returning to the login screen makes sense.
EDIT: too much "use"
Offline
Kingghidorah$ cat First.sh
#!/bin/bash
commands...
commands...
commands...exec Second.sh
Kingghidorah$ cat Second.sh
#!/bin/bash
commands...
commands...
commands...Kingghidora
Makes no sense doing this.
What you are doing with the 'exec' in this case is replacing the bash command interpreter by ... the bash command interpreter.
Doesn't the exec command in this case open Second.sh in a separate iteration of bash?
Be excellent to each other, and...party on, dudes!
BunsenLabs Forum Rules
Tending and defending the Flame since 2009
Offline
Doesn't the exec command in this case open Second.sh in a separate iteration of bash?
Ehh I don't think so... From the terminal(process 100), the first script is launched as a child (process 101) ...then the second.sh script is launched in place of the first script (101). So second.sh's process becomes process 101. Then once it's run, it dies, returning the user to process 100 (the terminal). Do I have this right?
Horizon_Brave wrote:....
I can't think of a real reason to use it in a script. ....Wrapper scripts commonly use `exec`
So wrapper scripts... So what is it that causes exec to be common in wrappers? Here's a very generic wrapper:
#!/bin/bash
# logging-wrapper.sh
# Generic shell wrapper that performs an operation
#+ and logs it.
DEFAULT_LOGFILE=logfile.txt
# Set the following two variables.
OPERATION=
# Can be a complex chain of commands,
#+ for example an awk script or a pipe . . .
LOGFILE=
if [ -z "$LOGFILE" ]
then # If not set, default to ...
LOGFILE="$DEFAULT_LOGFILE"
fi
# Command-line arguments, if any, for the operation.
OPTIONS="$@"
# Log it.
echo "`date` + `whoami` + $OPERATION "$@"" >> $LOGFILE
# Now, do it.
exec $OPERATION "$@"
# It's necessary to do the logging before the operation.
So from the above, the 'wrapping' is basically the setting up of some variables and arguments to pass to $OPERATION. Once the exec is run, this wrapper script is then replaced by the $OPERATION process.
So after $OPERATION then runs, it will return to the bash shell. My question is that if we took out the exec in front of operation, this wrapper script would have ended anyway, so after $OPERATION complete, it would have returned to bash anyway?
"I have not failed, I have found 10,000 ways that will not work" -Edison
Offline
Often it's for tidyness or efficiency. If you launch a process from a script without exec, the parent script will still be around, waiting for its child to exit. There will be an extra process running on your system.
Sometimes you actually want a wrapper to stay around to do some cleaning up after the child has finished, but if not, an exec will just move everything over to the new process.
I imagine this is what things like gmrun or the openbox menu are doing when they launch something, but not with bash of course.
In your example $OPERATION will return to the bash shell only if the wrapper was launched from a terminal. Otherwise it will just exit. Without exec it will return to the launching script...which will just exit. So, often the difference is small.
...elevator in the Brain Hotel, broken down but just as well...
( a boring Japan blog (currently paused), now on Bluesky, there's also some GitStuff )
Offline
Horizon_Brave wrote:HoaS, Okay, I suppose that makes sense but is it really that bad to have the user still logged in?
No, not at all.
It's simply a matter of preference -- usually, logging out of the x session would mean that the user has finished using the computer so returning to the login screen makes sense.
EDIT: too much "use"
But I DO remain logged in after an x session is terminated. And I do run my window managers using the exec command in xinitrc. Perhaps I am misunderstanding you? Why would terminating the x server result in your being logged out? I'm on a different page. Are you referring to launching the server in bash_profile or somesuch?
Last edited by jdonaghy (2016-02-02 20:20:55)
Offline
But I DO remain logged in after an x session is terminated. And I do run my window managers using the exec command in xinitrc. Perhaps I am misunderstanding you? Why would terminating the x server result in your being logged out?
:8
Good catch, thanks jdonaghy!
My mistake, I was thinking of my ~/.zprofile which starts the x session automatically for me when I (auto)login:
[[ -z $DISPLAY && $XDG_VTNR -eq 1 ]] && exec startx
If just `startx` is used without the exec() command then killing x returns me to the console still logged in.
exec() is used in .xinitrc for the application that kills the x session when it is terminated, ie, the window manager.
Any lines in ~/.xinitrc after exec() are not parsed until the exec()'d program terminates.
EDIT: Yes, your edit is spot-on.
Last edited by Head_on_a_Stick (2016-02-02 20:26:40)
Offline
[[ -z $DISPLAY && $XDG_VTNR -eq 1 ]] && exec startx
If just `startx` is used without the exec() command then killing x returns me to the console still logged in.
exec() is used in .xinitrc for the application that kills the x session when it is terminated, ie, the window manager.
Any lines in ~/.xinitrc after exec() are not parsed until the exec()'d program terminates.
@ everyone, thanks for the responses people!!
HoaS, hmm... two things though...
1. You say that in your ~/.zprofile if startx didn't have the exec command in front, then once you kill x, it returns you to the console. That would be true, if you didn't run the ~/.zprofile with exec in the first place right? Because if you did, then the bash shell would have become the ~/.zprofile process, which in turn became the x session.
2. Are you sure that lines *AFTER* exec can be run at all. If the script is turned into the process that it calls, it doesn't exist anymore once that process is exited. So anything below exec is lost right?
"I have not failed, I have found 10,000 ways that will not work" -Edison
Offline
Any lines in ~/.xinitrc after exec() are not parsed until the exec()'d program terminates.
Not even then, I'm pretty sure, and as Horizon_Brave has noticed.
...elevator in the Brain Hotel, broken down but just as well...
( a boring Japan blog (currently paused), now on Bluesky, there's also some GitStuff )
Offline
Head_on_a_Stick wrote:Any lines in ~/.xinitrc after exec() are not parsed until the exec()'d program terminates.
Not even then, I'm pretty sure, and as Horizon_Brave has noticed.
I think I'm more shocked that I actually noticed this, and was right! So it's true..I AM learning!
I'm too tired tonight...but I do have questions about the other 'side' of the exec command..I'll post tomorrow....Redirection still scares me.
Last edited by Horizon_Brave (2016-02-03 05:24:40)
"I have not failed, I have found 10,000 ways that will not work" -Edison
Offline
1. You say that in your ~/.zprofile if startx didn't have the exec command in front, then once you kill x, it returns you to the console. That would be true, if you didn't run the ~/.zprofile with exec in the first place right? Because if you did, then the bash shell would have become the ~/.zprofile process, which in turn became the x session.
I use zsh rather than BASH and this sources ~/.zprofile if it is run as an login shell, see zsh(1) et al
2. Are you sure that lines *AFTER* exec can be run at all. If the script is turned into the process that it calls, it doesn't exist anymore once that process is exited. So anything below exec is lost right?
lines following exec would be ignored
https://wiki.archlinux.org/index.php/Xinitrc
This has been proven *many* times in Arch forum threads
Offline
This has been proven *many* times in Arch forum threads
Yep that's what I was agreeing with. So I think the exec command by itself we've beaten to death.
Okay So part two! The Exec command used for redirection. First the quick and dirty of redirection
3 Types of default directions:
standard input ( stdin) < Default is from the keyboard.
standard output ( stdout) > Default is to the monitor.
standard error ( stderr) 2> Default is also to the monitor.
So whenever you see < always think input..not nescessarily from the keyboard, but by default it is.
When using redirector symbols like >, <, and & we need to use representations of the file descriptors.
0 = stdin
1 = stdout
2 = stderr
Generally, you read it as one statement. For example:
make 1> results 2> ErrorReport.txt
Don't be a goofball like me, who was confused by trying to read it completely left to right. I somehow thought that 1> goes to results, which somehow pipes 2 to errorreport.
What this actually does is send the standard output (1) of the make command, to the results file. Also send the standard error (2) to Error Report. Both redirection actions apply to the first make command.
Note that the 1 in front of > is sort of optional. It's like in Algebra putting a 1 in from of a single variable. (Don't ask how I remembered anything about Algebra) The same applies to the stdin (<) You could if you want put <0 but it's 0 by default anyway.
2>1 may look like a good way to redirect stderr to stdout. However, it will actually be interpreted as "redirect stderr to a file named 1".
To actually accomplish sending stderr to stdout, you need to use the & symbol.
Any time you re-direct to ANY custom FD...you need to preface it with &.
Example:
>&3 correct
1>&7 correct
2>5 incorrect - why? Because doing this would open standard error to a file called 5.
Alright..so now let's finally get Exec involved.
In a script, when you redirect output to someplace, you do it on a line by line basis...Well that can get annoying quickly. Each time you want a command to send the output or errors someplace you'd have to constantly remind it where to send them. For example:
ls -al > ~/kingghidorah/file1.txt 2> /var/log/errors.txt
Then maybe later in the script you want to:
echo "some example text" >> /var/log/errors.txt
etc...etc.. You get the point, each time you have re-point the descriptors to the files that you want. I'd also have to remember to use the append (>>) symbol each time. With exec in a script, you can just do:
exec 1> ~/kinghidorah/file1.txt
And for the rest of the script any command that produces stdout, it'll be sent to the file1.txt.
You use exec in a shell script to "permanently" keep the redirection for the duration of the script's life.
So any thing using the same file descriptor, you don't have to explicitly re-create it. It also works for custom file descriptors.
You can exec 4>> /var/log/errors.txt
Now you're free to use file descriptor 4 to send output to.
echo "bunsenlabs" >&4
You know as I'm writing this I've answered like 90% of my own questions...Since I've come this far, I'll finish it up, the only question I have left is this:
To send stdout to one process and stderr to another process, we have to use the syntax:
exec > >(grep xyz) 2> >(/dev/null)
The exec command (or it could be any command) sends it's stdout to the >( ) operator. What is this >(..commands..) syntax? Why doesn't this work as:
echo abc > $(grep xyz)
Doesn't the $(...) syntax mean the output of a command? So what does the >(...) syntax do? I can't find any documentation for it. What's the name for this syntax?
Anyway thanks everyone, this post turned out to be more of a tutorial rather than the list of questions I had...but like I said, I answered them all as I was writing this lol.
Last edited by Horizon_Brave (2016-02-03 20:02:28)
"I have not failed, I have found 10,000 ways that will not work" -Edison
Offline
Also...if anyone is willing to glance that over, to let me know if I have the syntax correct, that'd be appreciated, but the main thing is the question at the end...
"I have not failed, I have found 10,000 ways that will not work" -Edison
Offline
echo abc > $(grep xyz)
This is meaningless I'm afraid. $(command) is a string that encapsulates the standard output of command. You can't redirect anything to a string! It must be a file, or something that looks like a file and can hold the content you send to it.
Now the >(command1;command2...) and <(command;more...) syntax: this is called process substitution and does look like a file to things that send (with > ) or receive (with < ) to/from it. See:
http://mywiki.wooledge.org/ProcessSubstitution
http://wiki.bash-hackers.org/syntax/exp … proc_subst
...elevator in the Brain Hotel, broken down but just as well...
( a boring Japan blog (currently paused), now on Bluesky, there's also some GitStuff )
Offline
I don't care what you do at home. Would you care to explain?
Offline