The way it's supposed work is that, at the point when you get a shell prompt, both .profile
and .bashrc
have been run. The specific details of how you get to that point are of secondary relevance, but if either of the files didn't get run at all, you'd have a shell with incomplete settings.
The reason terminal emulators on Linux (and other X-based systems) don't need to run .profile
themselves is that it will normally have been run already when you logged in to X. The settings in .profile
are supposed to be of the kind that can be inherited by subprocesses, so as long as it's executed once when you log in (e.g. via .Xsession
), any further subshells don't need to re-run it.
As the Debian wiki page linked by Alan Shutko explains:
"Why is .bashrc
a separate file from .bash_profile
, then? This is done for mostly historical reasons, when machines were extremely slow compared to today's workstations. Processing the commands in .profile
or .bash_profile
could take quite a long time, especially on a machine where a lot of the work had to be done by external commands (pre-bash). So the difficult initial set-up commands, which create environment variables that can be passed down to child processes, are put in .bash_profile
. The transient settings and aliases which are not inherited are put in .bashrc
so that they can be re-read by every subshell."
All the same rules hold on OSX, too, except for one thing — the OSX GUI doesn't run .profile
when you log in, apparently because it has its own method of loading global settings. But that means that a terminal emulator on OSX does need to run .profile
(by telling the shell it launches that it's a login shell), otherwise you'd end up with a potentially crippled shell.
Now, a kind of a silly peculiarity of bash, not shared by most other shells, is that it will not automatically run .bashrc
if it's started as a login shell. The standard work-around for that is to include something like the following commands in .bash_profile
:
[[ -e ~/.profile ]] && source ~/.profile # load generic profile settings
[[ -e ~/.bashrc ]] && source ~/.bashrc # load aliases etc.
Alternatively, it's possible to have no .bash_profile
at all, and just include some bash-specific code in the generic .profile
file to run .bashrc
if needed.
If the OSX default .bash_profile
or .profile
doesn't do this, then that's arguably a bug. In any case, the proper work-around is to simply add those lines to .bash_profile
.
Edit: As strugee notes, the default shell on OSX used to be tcsh, whose behavior is much saner in this respect: when run as an interactive login shell, tcsh automatically reads both .profile
and .tcshrc
/ .cshrc
, and thus does not need any workarounds like the .bash_profile
trick shown above.
Based on this, I'm 99% sure that the failure of OSX to supply an appropriate default .bash_profile
is because, when they switched from tcsh to bash, the folks at Apple simply didn't notice this little wart in bash's startup behavior. With tcsh, no such tricks were needed — starting tcsh as a login shell from an OSX terminal emulator Just Plain Works and does the right thing without such kluges.
You're interpreting the man page wrong. Firstly, the part about --
signalling the end of options is irrelevant to what you're trying to do. The -c
overrides the rest of the command line from that point on, so that it's no longer going through bash's option handling at all, meaning that the --
would be passed through to the command, not handled by bash as an end of options marker.
The second mistake is that extra arguments are assigned as positional parameters to the shell process that's launched, not passed as arguments to the command. So, what you're trying to do could be done as one of:
/bin/bash -c 'echo "$0" "$1"' foo bar
/bin/bash -c 'echo "$@"' bash foo bar
In the first case, passing echo the parameters $0
and $1
explicitly, and in the second case, using "$@"
to expand as normal as "all positional parameters except $0". Note that in that case we have to pass something to be used as $0
as well; I've chosen "bash" since that's what $0
would normally be, but anything else would work.
As for the reason it's done this way, instead of just passing any arguments you give directly to the command you list: note that the documentation says "commands are read from string", plural. In other words, this scheme allows you to do:
/bin/bash -c 'mkdir "$1"; cd "$1"; touch "$2"' bash dir file
But, note that a better way to meet your original goal might be to use env
rather than bash
:
/usr/bin/env -- "ls" "-l"
If you don't need any of the features that a shell is providing, there's no reason to use it - using env
in this case will be faster, simpler, and less typing. And you don't have to think as hard to make sure it will safely handle filenames containing shell metacharacters or whitespace.
Best Answer
This is better done from a script though with
exec $0.
Or if one of those file descriptors directs to a terminal device that is not currently being used it will help - you've gotta remember, other processes wanna check that terminal, too.And by the way, if your goal is, as I assume it is, to preserve the script's environment after executing it, you'd probably be a lot better served with :
The shell's
.dot
andbash's source
are not one and the same - the shell's.dot
is POSIX specified as a special shell builtin and is therefore as close to being guaranteed as you can get, though this is by no means a guarantee it will be there...Though the above should do as you expect with little issue. For instance, you can :
The shell will run your script and return you to the interactive prompt - so long as you avoid
exit
ing the shell from your script, that is, or backgrounding your process - that'll link your i/o to/dev/null.
DEMO:
MANY
JOBS
It's my opinion that you should get a little more familiar with the shell's built-in task management options. @Kiwy and @jillagre have both already touched on this in their answers, but it might warrant further detail. And I've already mentioned one POSIX-specified special shell built-in, but
set, jobs, fg,
andbg
are a few more, and, as another answer demonstratestrap
andkill
are two more still.If you're not already receiving instant notifications on the status of concurrently running backgrounded processes, it's because your current shell options are set to the POSIX-specified default of
-m
, but you can get these asynchronously withset -b
instead:A very fundamental feature of Unix-based systems is their method of handling process
signals
. I once read an enlightening article on the subject that likens this process to Douglas Adams' description of the planet NowWhat:This is referring to
kill signals
.At least for me, the above quote answered a lot of questions. For instance, I'd always considered it very strange and not at all intuitive that if I wanted to monitor a
dd
process I had tokill
it. After reading that it made sense.I would say most of them don't try to adapt for good reason - it can be a far greater annoyance than it would be a boon to have a bunch of processes spamming your terminal with whatever information their developers thought might have been important to you.
Depending on your terminal configuration (which you can check with
stty -a
),CTRL+Z
is likely set to forward aSIGTSTP
to the current foreground process group leader, which is likely your shell, and which should also be configured by default totrap
that signal and suspend your last command. Again, as the answers of @jillagre and @Kiwy together show, there's no stopping you from tailoring this functionality to your purpose as you prefer.SCREEN JOBS
So to take advantage of these features it's expected that you first understand them and customize their handling to your own needs. For example, I've just found this screenrc on Github that includes
screen
key-bindings forSIGTSTP
:That would make it a simple matter to suspend a process running as a child
screen
process or thescreen
child process itself as you wished.And immediately afterward:
OR:
Would foreground or background the process as you preferred. The
jobs
built-in can provide you a list of these at any time. Adding the-l
operand will include pid details.