Shell login - profiles and scripts
Linux-related notes
Shell, admin, and both:
|
This is mostly about bash's behaviour, and tweaking it.
It doesn't touch much on shell programming or syntax.
Files that are sourced, and when
(See also X startup scripts)
Note that the below mostly details the bash / bourne family.
Other shells, say zsh, ksh, csh, tcsh, and others, work differently enough to merit their own summary (By someone who uses them. Details welcome).
tl;dr:
- graphical shells typically do not run login shells, unless forced to (verify)
- which often means you don't want to make the distinction of interactive and login yourself
- ...and put all the stuff you need for interaction in the run-for-interactive part, which for bash means bashrc
- assume profile gets run once per shell, while bashrc also gets run on subshells (if you use them)
- (you may care to avoid redefinitions sometimes)
- scripts aren't shells, and should explicitly source the environment they need, or may react differently when run by other people, from batch queues, services, cron, compilation environments, etc.
- often they need very little
- in some cases, environment modules are the thing that keeps you sane
- BASH_ENV is a nice tool for some cases
- ssh can be an exception case, at least under the covers. But usually does what you want.
Context: Login shell versus interactive shell
Each shell has two properties relevant to this discussion:
- login or non-login
- interactive or non-interactive
These are two distinct properties, so there are four combinations,
yet in most practice you consider one of two or three cases:
- first on a tty (login+interactive)
- 'interactive login shell', 'login shell', 'initial login shell' usually refer to this.
- includes
- those that are first on a shell, including hardware (text-mode) terminals
- those specifically requested to be login, e.g. bash -l or bash -login (e.g. VNC's .Xstartup often does this)
- shells implicitly created when switching users with su - username (su username gives a non-login shell), sudo -i
- (note: sudo's shorthand for login is -i, su's is -l. I consider that stupidly confusing.)
- not first on a tty (non-login interactive)
- includes
- non-interactive, e.g. scripts
- aside from scripts themselves, examples are:
- these do not implicitly read any configuration files (verify)
- (can be login, typically is not - mostly related to ssh[1])
Footnotes to that:
- GUI terminals
- many tend to start non-login interactive shells, apparently arguing that you start one login shell with the display manager, you still get the "once per graphical session" behaviour (verify)
- others choose to run login shells in each terminal window, arguging that a terminal window is a session, unrelated to the graphical one (also since graphical startup has its own rcfiles, e.g. xsession)
- SSH
- allocates a pseudoterminal, so is considered login
- somewhat manually imitates a local bash (and bash may be specialcased)
- so usually it's exactly the same, but sometimes it needs coaxing to behave quite the same as local shells
- tmux's idea seems to be that new shells should more predictably pick up new config this way
Checking for login / interactive shell
For bash, a quick copy-paste:
shopt -q login_shell && echo 'Login' || echo 'Not login'
[[ $- == *i* ]] && echo 'Interactive' || echo 'Not interactive'
login
For bash,
- shopt will mention either login_shell on or login_shell off
- In a test, shopt -q is often nicer - it tells you in the return code, and is silent.
Doing this in a more portable way (beyond bash) is a bit harder [2]
Apparently a leading - in the $- value also indicates login?(verify)
interactice
In bash, look whether special bash variable $- contains i, e.g.
case $- in
*i*) echo 'Interactive' ;;
*) echo 'Not interactive' ;;
esac
In many shells, checking whether there is a variable like PS1 also tends to work well
Distinctions between .bashrc and similar files
Quick and dirty summary
Note that while some details below assume bash, some go into details beyond bash.
So when it says "bashrc", you may want to read it as "the applicable shell(-specific) rc files"
- PAM hooks tend to happen before the below
- but is only for environment, not for scripts
- and only happens at auth time(verify)
- profile should set up everything that gets initialized once and may be used down the line
- once per terminal, at login time.
- bashrc is read on "an interactive shell that is not a login shell"
- in practice it's fairly common to put everything to be run for all shells and subshells into .bashrc, to happen at each shell invocation.
- and to have profile explicitly source bashrc if it exists.
- The distinction betweenthe last two is -- roughly -- login shells versus interactive shells.
- some GUI terminals may (unlike historical terminals) specifically avoid a login shell
- Scripts are different
- SSH is different (can be, anyway)
- cron is different
Admins
- often want to put things in /etc so that all users inherit said configuration.
- ...and should check exactly what the distro does in terms of what is sourced from what
- /etc/profile.d/ is quite convenient if your disto is set up to use it
For users, putting stuff in your personal rc files (e.g. ~/.bashrc for bash users) is the easiest.
- (though technically extending PATH is best put in your profile, to avoid it filling up with duplicates in subshells)
Practical setup
More details
PAM /etc/environment
When PAM is configured to do this, it reads and sets the contents in the environment, before loading your shell.
This means
- it's a config file parsed for its key=value lines, not a sourced/executed script
- it's actually quite useful to set environments in all shells, including exotic ones.
- it only applies when authenticating (using PAM)
- The next graphical login will (verify)
- A ssh (e.g. to localhost) will.
- Running bash (-i or -l) won't.
- Running an xterm (-i or -l) won't (verify)
While for larger scales it can be a useful tool,
and sometimes a more secure one,
it's not widely used on small setups because it's yet another thing to consider (and can only set env).
Things called profile
Things called profile are intended to be a sourced only by login shells
- ~/.profile for user-specific stuff (but see the next point)
- /etc/profile for system stuff
profiles for for specific shells
- bash_profile (and other specific-shell profiles) are intended for run-once-per-terminal things
- ...that need shell-specific syntax/features
Sometimes with footnotes. For example, bash looks for ~/.bash_profile, ~/.bash_login, ~/.profile - in that order and uses only the first one of these it finds
That allows options like
- only having a .profile, shared between some shells (that are still similar enough to share its syntax)
- having ~/.bash_profile
- that has some of its own things
- and then explicitly sources the still-shared .profile
- and/or specific .bashrc (in that order)
- ..but frankly, try to keep this as simple as possible
- arguably most things belong either in .profile or .bashrc
Side note: most shells do not have shell-specific profile file in /etc
profile.d
If /etc/profile.d/ exists, it will be explicitly sourced from /etc/profile
This is a relatively recent convention - but also common because it's required by LSB.
(This (and other .d things) is particularly convenient for package management, which can now add/remove its parts by placing/remocing a file, rather than a bunch of lines that will be harder to add/remove from a singular file.)
Sourcing them from bourne-family amounts to:
for i in /etc/profile.d/*.sh ; do if [ -r "$i" ]; then . $i fi done
Note that since it specifically looks for .sh, and e.g. csh looks for .csh, this also helps organize shell-specific things a bit.
Note that sh still means "any /bin/sh", including minimal ones like dash.
bashrc and similar
bashrc is intended for every interactive bash shell (and gets sourced each subshell)
- ...and by default not sourced from login shells
- ...but most distros add a source ~/.bashrc to the relevant profile (~/.profile or ~/.bash_profile) because it's useful for whatever they should share
- yet some (e.g. OSX's Terminal) do not
- /etc/bash.bashrc for system stuff
- ~/.bashrc are intended for interactive shells
In practice:
- Many distros set up /etc and account skeletons (/etc/skel) where: (verify)
- ~/.profile OR ~/.bash_profile explicitly sources ~/.bashrc
- /etc/profile OR ~/.bashrc explicitly sources /etc/bashrc (verify)
- profile stuff (included by login shells) tends to be the most universal
- bashrc will be there for all interactive shells
- so aliases, EDITOR, prompt, etc. make sense here
- For "add to environment" the profile/bashrc distinction matters less, because it tends to get inherited everywhere you want anyway
- though PATH=$PATH:more is best placed in profile to avoid repeated adds
- the applicable things in /etc/ will often specifically not do most of their work when they happen to be sourced from scripts.
- via something like [ -z "$PS1" ] && return, or parts wrapped by if [ "$PS1" ]
- ...in theory you could have a specific section in there for just scripts.
- It's generally not best practice, though, in part because it means that file needs more protection (e.g. avoid output unless [[ $- == *i* ]]. Also because:
- scripts should never count on environment, at least not to run at all
- so if you need specific environment, do it explicitly. Usually sourcing is best for your sanity
- that includes PBS, MPI stuff
- in some cases, a specific /etc/profile.d file might be well suited
Misc notes:
- cron explicitly uses a restricted environment (and often runs scripts), so usually none of this applies
(which is a good idea for safety)
- so explicitly include/source any env you need
- You usually don't need to bother with login and logout rcfiles at all
- .login
- apparently the C-shell convention, practically the same as .profile
- to keep things simpler, avoid unless you need it
- .bash_login was apparently an early attempt to be more compatible with C-shell - that didn't really work out and you can ignore it
Non-bash
Hardware terminal login
Just for context, hardware terminals are handled by a process historically called getty [3]
getty is the thing that asks for username (just the username), and then executes login telling it that username.
login hooks in the rest - checks whether you need a password, and if so asks you for it (presumably these days hooks into PAM(verify)), and if satisfied hands off to your configured shell (often bash).
Bash does its startup thing, as mentioned above. In this case as a login shell (pretty much always, in this path?(verify)).
SSH
Much like the getty case, but with sshd taking the place of getty, and with some of its own behaviour.
sshd invokes bash as a login shell (at least by default), which is what you'd expect.
ssh agent, if any, should be set up in bash_profile
If a command is given, it is executed instead of a login shell, not within a shell, so none of these apply.
Some added details:
- the ssh client may be sending some environment from the client side - see SendEnv and AcceptEnv [4]
On a few programs having more requirements
While relatively rare, and a little unhandy, there are a few things that run themselves remotely over SSH, and as such expect it to behave to certain restrictions.
rsync is one such example. if your profile spits out things,
On cron
Basically, these
- are run as scripts (not under shells, so assume no implicit profile and rc sourcing)
- have system environment stripped for security reasons (verify)
If you want to include a certain shared environment, consider BASH_ENV
See also Automation,_remote_management,_configuration_management#Cron_and_environment
On graphical login
Tends to have its own rc files, making the distinction relatively moot -- except if you also want the same thing in SSH logins.
X terminals within graphical logins means the window manager creating a process (e.g.) via forking, which is relevant in that it inherits environment (like DISPLAY).
The shell here will often not be a login shell, due either to historic reasons,
or to specific choice by the terminal emulator.
You can configure most it to start login shells.
On BASH_ENV
Semi-sorted
If you want to know what exactly your specific shell is doing and sourcing, you can watch it open files with something like
strace -f -e trace=file bash -l -c echo 2>&1 | grep open | egrep -v '(/lib|/proc|locale|[.]so|resumed)'
- where
- the -l in this example specifically tests a login shell (-c echo just makes the new shell quit after it does nothing worth mentioning)
- the greps take out most stuff you're probably not interested in
See also (files)
TODO: read:
Config files
Potentially useful fragments for your bashrc and bash_login
Note: The difference between bashrc and bash_login is that bashrc is for interactive shells (including xterms, I believe), and the second for login shells (including screen windows).
In practice you may want to put things into both, or create a script of common things that you call from both.
grep results in color
When it is not the system default, you can get grep to output colors when it is the main command (not when used in a pipe, based on autodetection), using:
export GREP_OPTIONS='--color=auto'
If you want it even in pipes you can set it to always. Can be nice e.g. for less, but not everything you pipe into understands the escape codes. Arguably always is best used in aliases, not as a default.
You can change the colors it uses using GREP_COLORS (or the deprecated GREP_COLOR), in which you can set the color of various different parts of the grep results; see the man page.
History stuff
Searching the history
CtrlR is an interactive search, from most recent to older (press CtrlR again).
Note that if you press enter you immediately execute the command; you often want to press an arrow key or Tab instead so that you can edit it first.
For a less interactive thing, there's history
Cleaner history
You can specify things that should not be logged, which can be handy when arrow-upping for recent interesting commands as well as using Ctrl-R to search it.
Example:
export HISTIGNORE="&:cd:mc:top:htop:svn st:exit:mutt:ls:[bf]g *|[bf]g"
In this example:
- The & means 'matches the previous line', which avoids adjacent duplicates from being logged.
- most commands here are specified to be matched exactly, so when you use them with arguments they are still saved.
- ...whereas bg and fg are explicitly ignored for all cases.
Also, HISTCONTROL
- is a colon-sperated list of options that further controls how and what to save
- ignoreboth shorthand for ignorespace:ignoredups
- ignorespace Lines that start with a space are not saved
- ignoredups causes lines matching the previous history entry to not be saved. A value of
- erasedups previous lines matching current line are removed from history before the current line is saved.
Longer history
Note that the meaning of values other than numbers ≥ 0 has changed somewhat over time, read your man bash
HISTSIZE
- the amount of recent history entries that a bash process keeps
- default: 500
- setting unlimited history depends a little on bash version, so check man bash to be sure (but it'll be negative or blank)
- 0 means don't save
- my man page saus "Numeric values less than zero result in every command being saved on the history list (there is no limit).
HISTFILESIZE
- the amount of a specific shell's own history, in lines, to write to HISTFILE (when the running shell exits)
- default: value of HISTSIZE, unless set
- 0 means truncate to empty file
- my man page saus "Non-numeric values and numeric values less than zero inhibit truncation"
HISTFILE
- the file that the the running shell writes its own history to (when it exits)
- default: ~/.bash_history
- note: unsetting means 'don't save this shell's history'
histappend (shell option) - append to central history instead of replacing it
The basic behaviour:
- On startup, bash loads HISTFILE
- apparently the most recent HISTFILESIZE lines (verify)
- each line is saved to in-memory history (adhering to HISTCONTROL and HISTIGNORE)
- When it exists, bash
- writes its own in-memory history to HISTFILE (overwrite/append, according to histappend)
- then truncates that file to have at most HISTFILESIZE lines (unless HISTFILESIZE is not set)
You can force bash to write to and update from HISTFILE using
history -a; history -n
(I doubt there is file locking going on, so PROMPT_COMMAND=’history -a; history -n’ might lead to occasional clobbering(verify))
Note on export, setenv, etc
In bash, export replaces a variable in the current environment. Other shells may use setenv or set.
#usually written as:
export PATH=$PATH:/bla/bla
#which is equivalent to a local set followed by an explicit export
PATH=$PATH:/bla/bla
export PATH
Export means that it will inherit (get copied) to subenvironments. (I remember there being some pesky details. I should check up on them.)
Useful things to export include:
- path to look for things to execute (PATH)
- almost everything in profile/bashrc files, e.g.
- program defaults (e.g. GREP_COLOR=auto, LESS="-aXz-5j3", etc.)
- programs' home directories (eg. GMT_HOME, GRASS_HOME, JDK_HOME)
- an added directory to have private libraries (LD_LIBRARY_PATH)
- compiler options (CFLAGS, CPPFLAGS, LDFLAGS for adding additional include and library paths when you want to compile things)
Setting PATH
Fairly simple. To add /etc/local/bin/myprogrambins/ and your $HOME/bin to the PATH, for example, do:
export PATH=$PATH:/etc/local/bin/myprogrambins/:$HOME/bin
This preserves the current path and appends the new one. It is a safe default to add to the end of this list in case of name collisions; the first match in the list will be used. This can be exploited for good (perhaps sneaking in colorgcc as default gcc behaviour) and evil (many other cases).
It is not advised to do:
export PATH=$PATH:.
...just to get windows/DOS-like behaviour in that you can run executables from the current directory without having to append a ./. You may get randomly strange directory-dependent behaviour. Doing this ranges from useful-when-careful to annoying to a potential security problem.
Terminal type
See terminal type
setting your prompt
(See also e.g. [5])
You usually see what is set in PS1, and you see PS2 if you have multi-line strings and the sort. You're not likely to ever see PS3 or PS4.
It looks like the internal prompt variables (user, host, working directory, date, time, and things like \$; see PROMPTING in man bash) and escapes are evaluated after each shell command you give, while not everything is, and possibly not under all conditions. See the PROMPT_COMMAND for a workaround.
Funky things
Note on using/printing escapes
You can use escape sequences to give ANSI color commands, set the xterm title, move/save/restore the cursor, command a wrapping screen, and other such things.
Note on \[ and \]
Bash and some other shells (which?(verify)) treat \[ as "from here to a \] I shall interpret escapes", so that's where you usually put them.
Notes:
- These ranges are not counted as printable characters (shouldn't be), which matters in line wrapping behaving sensibly.
- When you take take values from somewhere to be displayed as part of the prompt (expansion of hostname, cwd, etc.), you want values outside such a range, both for correct wrapping and to avoid strange interactions. If you want to do something to such values, add a sequence before and one after.
- There are escape sequences that contain ] and those that contain [. Yes indeed, that's bloody confusing :)
Note on \e versus \033
\e is a shell-specific (probably bash-specific (verify)) way of saying "I want a literal ESCape control character here."
A more compatible and slightly harder to read alternative is \033 (ESC is 033 in octal, 1B in hex, 27 in decimal)
Similarly, \a is an alternative to \007 (BEL).
If you want to experiment with escapes, you may want to know that you can force echo to interpret escapes by using -e, and sometimes -n, 'don't append newline' ). Note however that echo doesn't know \[ and \].
Funky things: Setting the shell's title
ESC, ], 0, ;, titlestring, BEL
The text inside is interpreted by teminals that understand titles, such as most graphical terminals.
For example, you could prepend this to your real prompt:
"[\033]0;\u@\H:\w\007\]"
for something like root@example.com:/var
Funky things: setting the screen window's title
ESC, k, titlestring, ESC, \
This is the title you see when you list the screens (using Contol-a "), and can set using Control-A Shift-A.
For a prompt, and with escaping inside a "-quoted string, this works out to, for example:
\[\033k \u, in \w \033\\\]
When you also want to make screen change the X window(-as-in-graphical-window) title according to which screen you are in, you want to tell screen to use its hardline tricks, via .screenrc. See the basic example at screen.
Example
Note that since some older and barer terms may respond badly you should put fancy stuff on a condition, by using something like the following in your bash startup:
case $TERM in
screen*)
PS1="\[\033]0;\u on \H\007\]\[\033k\]\w\[\033\\\\\]\u@\H:\[\033[1;37m\]\w\[\033[37m\] \$ "
;;
xterm*|rxvt*)
PS1="\[\033]0;\u on \H, in \w\007\]\u@\H:\[\033[1;37m\]\w\[\033[37m\] \$ "
;;
*)
# avoid funky things when you are not sure about the capabilities:
PS1="\u@\H:\w \$ "
;;
esac
You may want \w (working directory) if you come from windows/DOS or perhaps regardless, though you get used to the non-clutter and remembering where you are. I just decided this format may be useful as it mimics the format scp uses, so it could be useful for copying things about.
If you want to set both screen's window titles and set the window window title, you could e.g.
- 'user on host' in the window title via PS1
- set the working directory as the screen window title,
- use screen's hardstatus feature to prepend <something like>'[0: /var]' (that is, '[screenwindownum: screenwindowtitle]' ) to the window title.
The result is that screen shows "/var/www" and the whole window shows "[0: /var/www] root on sparrow"
You could have something like:
Extra evaluation
Setting PROMPT_COMMAND allows you to evaluate/execute something before every command -- though note that this is potentially slow.
For example, you could do PROMPT_COMMAND="echo -n 'Groups: '; id -G -n"
A common use is to change PS1 every prompt, for example...
- showing the current directory's size
- make the prompt/title change with variables that aren't part of the \u-style thing bash itself replaces
- showing the last command's return code ($? in bash)
- using whoami to show things in red if you're root (though it's simpler to have root's profile/bashrc could just set this explicitly)
You can set the PROMPT_COMMAND variable to
- a string to evaluate, including the path to a script
- a bash function, so you can write potentially involved code, such as the following excessive example:
promptFunc() {
case $TERM in
xterm*|rxvt*|screen*)
PS1="\[\033[0;32m\][\D{%a, %H:%M}] \[\033[1;34m\]\u@\H\[\033[0m\]:\[\033[1;37m\]\w\[\033[0m\] " ;;
*)
PS1="[\A] \u@\H:\w " ;;
esac
# size of immediate entries (i.e. recursive)
DIRSIZE=$(ls -l | awk '/^[dlpscb\-][rsS\-][wsS\-][xtT\-]/{totalsize+=$5} END{printf("%d",totalsize)}');
if [ $DIRSIZE -ge 1073741824 ]; then
let DIRSIZE=$DIRSIZE/1073741824;DIRSIZE="${DIRSIZE}GB"
else
if [ $DIRSIZE -ge 1048576 ]; then
let DIRSIZE=$DIRSIZE/1048576;DIRSIZE="${DIRSIZE}MB"
else
if [ $DIRSIZE -ge 1024 ]; then
let DIRSIZE=$DIRSIZE/1024;DIRSIZE="${DIRSIZE}KB"
else
DIRSIZE="${DIRSIZE}B"
fi
fi
fi
PS1="${PS1}($DIRSIZE) "
#append a red [root] if we are root
if [ `whoami` == "root" ]; then
PS1="$PS1\[\033[31m\][root]\[\033[0m\] "
fi
PS1="${PS1}\$\[\033[0m\] "
}
PROMPT_COMMAND=promptFunc
Notes:
- the fact that ls -l will happen all the time will make changing to directories with very many entries rather sluggish.
- it might be more robust to do the dirsize based on find ./* -prune -type f -printf "%s\n"
Colored text
See Escaping_and_delimiting_notes#ANSI_color
See also
- http://www.edoceo.com/liber/linux-bash-shell.php
- http://www-128.ibm.com/developerworks/linux/library/l-tip-prompt/
- The text prompt themer called Bashish
- https://en.wikipedia.org/wiki/ANSI_escape_code
setting DISPLAY
http://www.tldp.org/LDP/abs/html/sample-bashrc.html
Note that it is easy to mess with other logic to this effect, from the system or from ssh -X.
keybinds and convenience settings
http://www.tldp.org/LDP/abs/html/sample-bashrc.html
shopt
aliases, functions
See some examples at Command_line_and_bash_notes#Shell_aliases_and_functions
Arguably some should be system-wide scripts.
Colored ls
GNU ls listens to
- environment variable LS_OPTIONS for whether/when to use colors, probably export LS_OPTIONS='--color=auto'
- environment variable LS_COLOR for which colors to use
You may prefer to use dircolors for easier debugging of the contents of LS_COLOR.
dircolors reads its own configuration file and produces the sh-style/csh-style environment set line you'ld want in your profile.
- When fiddling with dircolors and you want to set it within the current shell, you can do something like: eval `dircolors -b /etc/dircolors`
- (the -b is for bash, -c is for csh. This is purely about how to set the environment variable)
There will often be some logic in the system-wide bashrc (or comparable for other shells) that calls dircolors and evaluates its output.
It may prefer
~/.dircolors
and fall back to: (verify)
/etc/dircolors /etc/DIR_COLORS
You can find defaults and examples in various places.
(See also LS_OPTIONS for other ls formatting options. I like -p)
Unsorted
http://www.faqs.org/docs/abs/HTML/files.html
http://www.mcs.vuw.ac.nz/technical/TechNotes/tn105/tn105-bashrc.html
http://aplawrence.com/Detective/shbash.html
http://aplawrence.com/Forum/dhart1.html
http://dev.gentoo.org/~ciaranm/configs/bashrc.html
http://davekaufman.net/node/246
http://www.ats.ucla.edu/at/beowulf/getting_started/user.bashrc.htm
http://overtone.org/articles/bashrc.php
http://www.chpc.utah.edu/docs/manuals/user_guides/arches/code/chpc.bashrc~
http://www.cs.swarthmore.edu/help/UU3/bashrc.html
Potentially useful scripting lines
See also Command_line_and_bash_notes#Shell_conditionals_and_scripting for more general sh/bash syntax notes
"stop now if we don't have this command"
tl;dr you want something like:
command -v pidof >/dev/null || { echo "cannot find pidof, aborting."; exit 1; }
While which seems the obvious choice, it is not as well behaved as you think.
There are other things that effectively do the same, that are shell builtins (so also avoid a process). If you want to support at least bash and sh, then command -v seems best behaved (defined by POSIX).
(Thanks to this stackoverflow summary)
error/default value if not specified
See Command_line_and_bash_notes#Error_if_not_set
Other shell tricks
special home directory files
.forward
Various mail daemons can be configured to look for this file when email is delivered to an account. If the file exists, the contents are treated as the mailboxes and/or email addresses to deliver the mail for.
It is faily common to forward(-and-delete) to a single remote email address, though you can also leave a copy in the account, etc.
See also:
.hushlogin
You can suppress the login banner by placing a file named .hushlogin in your home directory.
This seems a convention followed by various motd style things, but not by everything.
Other bash notes
Special variables
$0 script name $1, $2, $3, etc. first argument, second, third, etc. You may prefer ${1}, ${2}, etc. $@ List of all variables entered at the command line, as an array (See notes below) $* List of all variables entered at the command line, as a string (See notes below) $# number of command line arguments $$ PID of the current shell $! PID of the most recent (background?) command $? Exit code of the last (foreground/pipe) command $- current shell options
On $@ and $*
If you're just printing them, there is little difference
In scripts that should handle any file
- the difference between $*, $@ and "$@" matters.
- $* and unquoted $@ are basically equivalent, and usually wrong -- in that both give you sequences of non-whitespace, meaning this breaks on filenames with spaces.
- "$*" is all arguments as a single string. This is only sometimes what you want
- "$@" is an array of strings, which can contain spaces
There are further footnotes to use of $* / "$@" on commands.(verify)
But if you want to iterate over filename arguments, the basic form is:
for fn in "$@"; do echo $fn done
If you want to play with the variants:
echo '$*' for i in $*; do echo $i done echo '"$*"' for i in "$*"; do echo $i done echo '$@' for i in $@; do echo $i done echo '"$@"' for i in "$@"; do echo $i done
You may further care about Command_line_and_bash_notes#Conditional_replacement
exit from sourced file
use return
- e.g. if [ -n "___SOFTSETONCE" ]; then return; fi