10.1. bash shell environment
It is nice to have all these preset and custom aliases and variables, but where do they all come from ? Bash has a number of startup files that are checked (and executed) whenever bash is invoked. Bash first reads and executes /etc/profile. Then bash searches for .bash_profile, .bash_login and .profile in the home directory. Bash will execute the first of these three that it finds. Typically these files will expand your $PATH environment variable.
[paul@RHELv4u3 ~]$ cat .bash_profile | grep PATH PATH=$PATH:$HOME/bin
export PATH
[paul@RHELv4u3 ~]$
If this is an interactive shell, then bash will also execute .bashrc. In the case of Red Hat, the .bashrc file will source /etc/bashrc.
[paul@RHELv4u3 ~]$ cat .bashrc # .bashrc
# User specific aliases and functions
# Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc
fi
[paul@RHELv4u3 ~]$
When you exit the shell, then ~/.bash_logout is executed.
A similar system exists for the Korn shell with .kshrc and other files. Actually a similar system exists for almost all shells.
10.2. path
The $PATH variable is very important, it determines where the shell is looking for commands to execute (unless the command is built-in). The shell will not look in the current directory for commands to execute! (Looking for executables in the current directory provided an easy way to crack DOS computers). If you want the shell to look in the current directory, then add a . to your path.
[[paul@RHEL4b ~]$ echo $PATH
/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/paul/bin [paul@RHEL4b ~]$ PATH=$PATH:.
[paul@RHEL4b ~]$ echo $PATH
[paul@RHEL4b ~]$
Your path might be different when using su instead of su - because the latter will take on the environment of the target user. The root user will have some sbin directories added to the PATH variable.
[paul@RHEL3 ~]$ su Password:
[root@RHEL3 paul]# echo $PATH
/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin [root@RHEL3 paul]# exit
[paul@RHEL3 ~]$ su - Password:
[root@RHEL3 ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin [root@RHEL3 ~]#
10.3. Shell I/O redirection
The shell (and almost every other Linux command) takes input from stdin and sends output to stdout and error messages to stderr. Stdin is usually the keyboard, stdout and stderr are the screen. The shell allows you to redirect these streams.
10.3.1. output redirection
Stdout can be redirected with a greater than sign. While scanning the line, the shell will see the > sign and will clear the file.
[paul@RHELv4u3 ~]$ echo It is cold today! It is cold today!
[paul@RHELv4u3 ~]$ echo It is cold today! > winter.txt [paul@RHELv4u3 ~]$ cat winter.txt
It is cold today! [paul@RHELv4u3 ~]$
Let me repeat myself here: While scanning the line, the shell will see the > sign and will clear the file! This means that even when the command fails, the file will be cleared!
[paul@RHELv4u3 ~]$ cat winter.txt It is cold today!
[paul@RHELv4u3 ~]$ zcho It is cold today! > winter.txt -bash: zcho: command not found
[paul@RHELv4u3 ~]$ cat winter.txt [paul@RHELv4u3 ~]$
10.3.2. noclobber
This can be prevented by setting the noclobber option.
[paul@RHELv4u3 ~]$ cat winter.txt It is cold today!
[paul@RHELv4u3 ~]$ set -o noclobber
[paul@RHELv4u3 ~]$ echo It is cold today! > winter.txt -bash: winter.txt: cannot overwrite existing file [paul@RHELv4u3 ~]$ set +o noclobber
[paul@RHELv4u3 ~]$
The noclobber can be overruled with >|.
[paul@RHELv4u3 ~]$ set -o noclobber
[paul@RHELv4u3 ~]$ echo It is cold today! > winter.txt -bash: winter.txt: cannot overwrite existing file
[paul@RHELv4u3 ~]$ echo It is very cold today! >| winter.txt [paul@RHELv4u3 ~]$ cat winter.txt
It is very cold today! [paul@RHELv4u3 ~]$
10.3.3. append
You can always use >> to append output to a file.
[paul@RHELv4u3 ~]$ echo It is cold today! > winter.txt [paul@RHELv4u3 ~]$ cat winter.txt
It is cold today!
[paul@RHELv4u3 ~]$ echo Where is the summer ? >> winter.txt [paul@RHELv4u3 ~]$ cat winter.txt
It is cold today! Where is the summer ? [paul@RHELv4u3 ~]$
10.3.4. error redirection
Redirecting stderr is done with 2>. This can be very useful to prevent error messages from cluttering your screen. The screenshot below shows redirection of stdout to a file, and stderr to /dev/null. Writing 1> is the same as >.
[paul@RHELv4u3 ~]$ find / > allfiles.txt 2> /dev/null [paul@RHELv4u3 ~]$
[paul@RHELv4u3 ~]$ find / > allfiles_and_errors.txt 2>&1 [paul@RHELv4u3 ~]$
10.3.5. input redirection
Redirecting stdin is done with < .
[paul@RHEL4b ~]$ cat < text.txt one
two
[paul@RHEL4b ~]$ tr ’onetw’ ’ONEZZ’ < text.txt ONE
ZZO
[paul@RHEL4b ~]$
10.3.6. here document
The here document (sometimes called here-is-document) is a way to append input until a certain sequence (usually EOF) is encountered. The EOF marker can be typed literally or can be called with Ctrl-D.
[paul@RHEL4b ~]$ cat <<EOF > text.txt > one
> two > EOF
[paul@RHEL4b ~]$ cat text.txt one
two
[paul@RHEL4b ~]$ cat <<brol > text.txt > brel
> brol
[paul@RHEL4b ~]$ cat text.txt brel
[paul@RHEL4b ~]$
10.4. Confusing I/O redirection
The shell will scan the whole line before applying redirection. The following command line is very readable and is correct.
cat winter.txt > snow.txt 2> errors.txt
2> errors.txt cat winter.txt > snow.txt
Even this will be understood perfectly by the shell.
< winter.txt > snow.txt 2> errors.txt cat
So what is the quickest way to clear a file ?
>foo
10.5. Practice: more bash
1. Take a backup copy of /etc/bashrc /etc/profile ~/.profile ~/.bashrc ~/.bash_profile (put them in ~/profilebackups).
2. Set and export a variable named profwinner in all these scripts, the value is the name of the script (profwinner=etc_bashrc in /etc/bashrc, profwinner=dot_profile in ~/.profile, and so on)
3. Set a unique variable in all these scripts (etc_bashrun=yes in /etc/bashrc, dot_profilerun=yes in ~/.profile, and so on)
4. Log on to a tty and to a gnome-terminal, and verify the values of the variables you set in questions 2 and 3. Which of the scripts were executed ? Which not ? Which was executed last ?
5. Does it matter on which line we set our variables in .bash_profile and .bashrc ?
6. Where is the command history stored ? And what about command history for Korn users ?
7. Define an alias ’dog’ for the tac command in one of your profile scripts. Which script did you choose and why ?