- Page
- Discussion
- View source
- History
You do not have permission to edit pages, for the following reason:
The action you have requested is limited to users in the group trusted.
You can view and copy the source of this page:
”This is for stuff pertaining to Bash, but probably a lot of it pertains to other POSIX shells too. I only call it “Bash” because that’s what I use and I’m not sure if things work in other shells or not because I don’t use other shells.” {{cite web| url = http://www.ibm.com/developerworks/library/l-bash-parameters.html?ca=drs-| title = | author = | date = | accessdate = 2007-05-11 11:18| license = }} {{quotation}} The bash shell is available on many Linux® and UNIX® systems today, and is a common default shell on Linux. {{end quotation}} {{Has associated category|GNU/Linux command line}}GNU/Linux command line {{Has associated category|GNU/Linux}}GNU/Linux {{Has associated category|GNU/Linux}}Bash =Reference links= * [http://www.gnu.org/software/bash/manual/bashref.html gnu.org reference] * [http://www.tldp.org/LDP/Bash-Beginners-Guide/html/index.html tdlp.org: Bash Guide for Beginners] =Command history= Be efficient: reuse commands you’ve already typed. You can simply press Up to get back to your last command. Keep pressing up or down to browse through your [readline] history. If you know what the command you want to re-use starts with or if it contains some unique string of text, then check out “event designators”. If you don’t remember exactly what it looked like or how long ago you last used it or you just want to see a list of all the commands you’ve recently used, try the history
command. It’s neat! ==history
command== Typing history
alone, will show you your entire history … which may not be what you want, particularly if it’s 1000s of lines long! Instead, get in the habit of specifying a number as the argument, which will specify how many lines it returns. So if you do history 10
, you’ll get a list of the 10 most recent commands you’ve typed.
> history 10 1377 hg color 1378 hg unroller 1379 vim ~/.bashrc 1380 . ~/.bashrc 1381 h 1382 hg unroller 1383 history --help 1384 history -d 1293 1385 man history 1386 history 10
This is basically equivalent to just doing history | tail -n10
To ”execute” one of the commands listed in the history, just type !{line_number}
. For example, assumin the history above !1380
would execute the . ~/.bashrc
command. I’ve added these aliases to my ~/.bashrc to make it more convenient to work with the history
command:
alias hist='history' # Slightly shorter to type. alias his='history' alias hi='history' alias h='history 50' # Show about a page worth of history. This is what I'll want to do most of the time. alias hgrep='history|grep ' # List all command lines containing the search term. alias hg='history|grep '
man history
will take you to BASH_BUILTINS(1)
; from there, search for /^ *history
and you’ll jump right to the section. {{quotation}}
history [n] history -c history -d offset history -anrw [filename] history -p arg [arg ...] history -s arg [arg ...] With no options, display the command history list with line numbers. Lines listed with a * have been modified. An argument of n lists only the last n lines. If the shell variable HISTTIMEFORMAT is set and not null, it is used as a format string for strftime(3) to display the time stamp associated with each displayed history entry. No intervening blank is printed between the formatted time stamp and the history line. If filename is supplied, it is used as the name of the history file; if not, the value of HISTFILE is used. Options, if supplied, have the following meanings: -c Clear the history list by deleting all the entries. -d offset Delete the history entry at position offset. -a Append the âânewââ history lines (history lines entered since the beginning of the current bash session) to the history file. -n Read the history lines not already read from the history file into the current history list. These are lines appended to the history file since the beginning of the current bash session. -r Read the contents of the history file and use them as the current history. -w Write the current history to the history file, overwriting the history fileâs contents. -p Perform history substitution on the following args and display the result on the standard output. Does not store the results in the history list. Each arg must be quoted to disable normal history expansion. -s Store the args in the history list as a single entry. The last command in the history list is removed before the args
{{end quotation}} ==Options==
HISTCONTROL A colon-separated list of values controlling how commands are saved on the history list. If the list of values includes ignorespace, lines which begin with a space character are not saved in the history list. A value of ignoredups causes lines matching the previous history entry to not be saved. A value of ignoreboth is shorthand for ignorespace and ignoredups. A value of erasedups causes all previous lines matching the current line to be removed from the history list before that line is saved. Any value not in the above list is ignored. If HISTCONTROL is unset, or does not include a valid value, all lines read by the shell parser are saved on the history list, subject to the value of HISTIGNORE. The second and subsequent lines of a multi-line compound command are not tested, and are added to the history regard‐ less of the value of HISTCONTROL. HISTFILE The name of the file in which command history is saved (see HISTORY below). The default value is ~/.bash_history. If unset, the command history is not saved when an interactive shell exits. HISTFILESIZE The maximum number of lines contained in the history file. When this variable is assigned a value, the history file is truncated, if nec‐ essary, by removing the oldest entries, to contain no more than that number of lines. The default value is 500. The history file is also truncated to this size after writing it when an interactive shell exits. HISTIGNORE A colon-separated list of patterns used to decide which command lines should be saved on the history list. Each pattern is anchored at the beginning of the line and must match the complete line (no implicit ‘*’ is appended). Each pattern is tested against the line after the checks specified by HISTCONTROL are applied. In addition to the normal shell pattern matching characters, ‘&’ matches the previous history line. ‘&’ may be escaped using a backslash; the backslash is removed before attempting a match. The second and subsequent lines of a multi-line compound command are not tested, and are added to the history regardless of the value of HISTIGNORE. HISTSIZE The number of commands to remember in the command history (see HISTORY below). The default value is 500. HISTTIMEFORMAT If this variable is set and not null, its value is used as a format string for strftime(3) to print the time stamp associated with each history entry displayed by the history builtin. If this variable is set, time stamps are written to the history file so they may be pre‐ served across shell sessions.
==Event designators (! commands)==
Event Designators An event designator is a reference to a command line entry in the his- tory list. ! Start a history substitution, except when followed by a blank, newline, = or (. !n Refer to command line n. !-n Refer to the current command line minus n. !! Refer to the previous command. This is a synonym for â!-1â. !string Refer to the most recent command starting with string. !?string[?] Refer to the most recent command containing string. The trail- ing ? may be omitted if string is followed immediately by a new- line. ^string1^string2^ Quick substitution. Repeat the last command, replacing string1 with string2. Equivalent to ââ!!:s/string1/string2/ââ (see Mod- ifiers below). !# The entire command line typed so far.
Especially useful, I find, is the !? variety:
!?svn export !?svn export?:s/home/moo/ !?generate contr ./script/generate controller user
=Problem: Quoted single argument containing spaces is treated as multiple arguments=
action="svn ci -m 'My commit message'" cd /home/services/httpd/shared/include/ $action svn: Commit failed (details follow): svn: '/home/services/httpd/shared/include/commit' is not under version control
=Work smarter on the command line= == Repeat last argument with $_ ==
cp /some/long/path /some/other/long/path vim $_
is easier to type than
cp /some/long/path /some/other/long/path vim /some/other/long/path
Also:
cp a b c d e f /some/long/path/to/dest/folder/ cd $_
rather than
cp a b c d e f /some/long/path/to/dest/folder/ cd $_
Also, if you ever discover that a directory that you ”thought” existed (or should exist) ”doesn’t” exist…as in the following situation, this is a handy trick…
> cp dev/shell/config/irbrc dev/public/ruby/ cp: cannot create regular file `dev/public/ruby/irbrc': No such file or directory > mkdir $_ (try again)
===When last argument has spaces=== You can’t just do this, because for some reason, even though you escaped the space, $_ still treats those two words as separate arguments.
~ > mkdir Two\ Words ~ > cd $_ bash: cd: Two: No such file or directory ~ > mkdir 'Two Words' ~ > cd $_ bash: cd: Two: No such file or directory # It's exactly as if you'd done this: ~ > cd Two Words bash: cd: Two: No such file or directory ~ > echo $_ Words # See?
This is how you gotta do it (wrap $_ in double quotes):
~ > cd "$_" ~/Two Words >
=Positional parameters ($*)= ==$* / $@: What’s the difference?==
* Expands to the positional parameters, starting from one. When the expansion occurs within double quotes, it expands to a single word with the value of each parameter separated by the first character of the IFS special variable. That is, "$*" is equivalent to "$1c$2c...", where c is the first character of the value of the IFS variable. If IFS is unset, the parameters are separated by spaces. If IFS is null, the parameters are joined without intervening separators. @ Expands to the positional parameters, starting from one. When the expansion occurs within double quotes, each parameter expands to a sep‐ arate word. That is, "$@" is equivalent to "$1" "$2" ... If the double-quoted expansion occurs within a word, the expansion of the first parameter is joined with the beginning part of the original word, and the expansion of the last parameter is joined with the last part of the original word. When there are no positional parameters, "$@" and $@ expand to nothing (i.e., they are removed).
"$*"
is equivalent to "$1 $2 ..."
(assuming $IFS
is ‘ ‘). "$@"
is equivalent to "$1" "$2" ...
.
> echo "'"$IFS"'" ' '
See http://svn.tylerrick.com/public/examples/bash/CommandLineArguments-* for some good examples of when you would need to use “$@”. ==You can copy your own variables into the positional parameters== {{thread}} Before you do, though, be sure to make a backup:
original_params=("$@")
{{end thread}}
> set -- "a b" c > print_args $@ There are 3 args: $1=a $2=b $3=c
=How to get full path of script=
cd `pwd`/`dirname $0`/
Does this always work? Not when you have symlinks apparently… Lance came up with this… I’m not sure if he still believes it’s necessary… {{section category|sed}}
DIR=`ls -l \`pwd\`/\`dirname $0\`/ | grep "\`basename $0\` -> " | sed -e 's/^.* -> \(.*\)$/\1/' | xargs dirname`
=How can I start and immediately background 2 scripts (script1 & ; script2 &)?=
Doesn't work: $ ./script/server & ; tail -f log/development.log & -bash: syntax error near unexpected token `;' Works: $ ./script/server & tail -f log/development.log &
=What’s the difference between .bashrc and .bash_profile?= Here’s the thought process I use to keep things straight: *”’~/.bash_profile
”’: **This is ”only” sourced when you first log in with your user. **So put things there that you basically want to only run once per “login”… **For instance, additions to the $PATH environment variable. It’s better to put that here than in ~/.bashrc
because if you put it in ~/.bashrc
, you will keep adding to $PATH every time you su yourself
, I think. (Not that you probably do that very often.) So that can cause it to append the same thing to $PATH repeatedly (and unnecessarily), making it really long. *”’~/.bashrc
”’: **Things that it’s okay to do repeatedly / more often with no side-effects. **”Don’t” put $PATH additions here. **It’s okay to put aliases, bash functions, etc. here **It’s okay to set variables here, like $EDITOR When bash is invoked as an ”’interactive login shell”’, it reads and executes commands from: */etc/profile *~/.bash_profile *~/.bash_login *~/.profile When an ”’interactive (but non-login) shell”’ is started, bash reads and executes commands from: */etc/bash.bashrc *~/.bashrc Usually, I see a line in ~/.bash_profile that ”also” sources ~/.bashrc (so put things there that should happen no matter what) ! ”’interactive login shell”’:
> sudo su - tyler ~/.bash_profile ~/.bashrc ~/.bashrc
”’interactive (but non-login) shell”’
> sudo su tyler ~/.bashrc
Alex Zarutin at {{cite web| url = http://www.webservertalk.com/archive109-2005-1-898875.html | title = Unix Shell – Difference between .bashrc and .bash_profile?| date = | accessdate = 2007-03-13 15:42| author = | license = }}
contains a list of commands to be executed when you log in and contains a list of commands to be executed every time you open a new shell. There is a slight difference between them: is read once at the beginning of a session, whereas is read every time you open a new terminal (e.g. a new xterm window). In a traditional setup you would define variables like PATH in , and things like aliases and functions in . But since usually is pre-configured to read the content of anyway, you might as well save some effort and put all your configuration into .
http://www.linuxforums.org/forum/linux-newbie/1182-difference-between-bashrc-bash_profile.html : :.bashrc is only used when you start bash as a non-login shell. There are some other files and environment variables used, too. :A login shell is the shell you get when you log in, and that means that it sets up some extra things, like aliases, extra PATH elements and completion stuff, that you only use in interactive mode, while an ordinary shell is a shell that interprets shell scripts and such, where some aliases and completion stuff won’t be needed. A login shell might also print a greeting or so, and you probably won’t want that in a script interpreter. :Note, however, that a shell can be an interactive shell without being a login shell. That commonly includes the situations where the shell is invoked “under” a login shell, such as in X. All PATH elements and stuff have already been set up when the X session script runs, and therefore the shells started in xterms need not do it again. From `man bash` in the Invocation section:
A login shell is one whose first character of argument zero is a -, or one started with the –login option. An interactive shell is one started without non-option arguments and without the -c option whose standard input and error are both connected to terminals (as determined by isatty(3)), or one started with the -i option. PS1 is set and $- includes i if bash is interactive, allowing a shell script or a startup file to test this state. The following paragraphs describe how bash executes its startup files. If any of the files exist but cannot be read, bash reports an error. Tildes are expanded in file names as described below under Tilde Expansion in the EXPANSION section. When bash is invoked as an interactive login shell, or as a non-interactive shell with the –login option, it first reads and executes commands from the file /etc/profile, if that file exists. After reading that file, it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable. The –noprofile option may be used when the shell is started to inhibit this behavior. When a login shell exits, bash reads and executes commands from the file ~/.bash_logout, if it exists. When an interactive shell that is not a login shell is started, bash reads and executes commands from ~/.bashrc, if that file exists. This may be inhibited by using the –norc option. The –rcfile file option will force bash to read and execute commands from file instead of ~/.bashrc. When bash is started non-interactively, to run a shell script, for example, it looks for the variable BASH_ENV in the environment, expands its value if it appears there, and uses the expanded value as the name of a file to read and execute. Bash behaves as if the following command were executed: if [ -n “$BASH_ENV” ]; then . “$BASH_ENV”; fi but the value of the PATH variable is not used to search for the file name.
Floyd L. Davidson at {{cite web| url = http://www.webservertalk.com/archive109-2005-1-898875.html | title = Unix Shell – Difference between .bashrc and .bash_profile?| date = | accessdate = 2007-03-13 15:46| author = | license = }}
1) The profile file […] is read only by login shells. It should have things that initialize the terminal or otherwise need be done one time only when a user does a login. Typically, initializing a terminal is slow. Hence one common example might be “stty ^H erase”. Another example is “PATH=~/bin:$PATH”, which is quick and easy, but if done for every subshell adds unnecessary search elements to the PATH variable if subshells are layers deep. 2) The rc file is read by every interactive subshell (and not by login shells). It should have things that are needed by for interactive use, but are excess baggage for non-interactive subshells. Typically that would be the definition of aliases. … The basic idea, which made obvious sense back when the functionality was first added to /bash/, is to speed up shell initialization by compartmentalizing it. When a 10Mb disk was the norm, and it was *SLOW*, the time spent slowly reading in a large _~/.profile_ for every single shell invocation, the way /sh/ did, was significant and a very noticeable bottleneck. Today of course not only is the disk file many many times faster itself, but we have the kernel cashing oft used disk files and it can be assumed that for a typical /bash/ invocation all of the init files have already been cached in RAM, and no disk activity is even done.
Thorsten Kampe at {{cite web| url = http://www.webservertalk.com/archive109-2005-1-898875.html | title = Unix Shell – Difference between .bashrc and .bash_profile?| date = | accessdate = 2007-03-13 15:46| author = | license = }}
This is less efficient, as environment that is inherited is redefined. and expressions like PATH=/new/path:${PATH} get a /new/path added with every instance of nested bash’es.
That’s correct (but again a bash nuisance). Put all your stuff in ..bashrc and only those things only needed in a login shell in to ..bash_profile. My .bash_profile contains only “source ~/.bashrc”.
> echo $PATH | wc -c 425 [tyler: ~]> sudo su tyler [tyler: ~]> echo $PATH | wc -c 505 # it grows every time! [tyler: ~]> sudo su - tyler [tyler: ~]> echo $PATH | wc -c 265 # here it apparently gets reset!
=Syntax= ==Line continuation==
> echo "reverberate" \ > [prompts for input, allowing you to continue your command on the next line] reverberate
But this doesn’t work:
> echo "reverberate" # a comment \ reverberate [prints immediately]
Nor does this:
> echo "reverberate" \ # a comment reverberate [prints immediately]
It would be nice to be able to document each line in a multi-line command. For example:
sudo gem install --local pkg/OurExtensions-0.0.1.gem \ --rdoc # So you can test that the rdoc installs properly \ --test # So you can ensure that all the tests pass still \ --force # In case it's already installed
Is there anyway to do that? Make a nice well-documented multi-line comment? =={{section category|Escaping}} things== man bash
!, must be quoted to prevent history expansion. There are three quoting mechanisms: the escape character, single quotes, and double quotes. A non-quoted backslash (\) is the escape character. It preserves the literal value of the next character that follows, with the exception of . If a \ pair appears, and the backslash is not itself quoted, the \ is treated as a line continuation (that is, it is removed from the input stream and effectively ignored). Enclosing characters in single quotes preserves the literal value of each character within the quotes. A single quote may not occur between single quotes, even when preceded by a backslash. Enclosing characters in double quotes preserves the literal value of all characters within the quotes, with the exception of $, â, \, and, when history expansion is enabled, !. The characters $ and â retain their special meaning within double quotes. The backslash retains its special meaning only when followed by one of the following characters: $, â, ", \, or . A double quote may be quoted within double quotes by preceding it with a backslash. If enabled, history expansion will be performed unless an ! appearing in double quotes is escaped using a backslash. The backslash preceding the ! is not removed. The special parameters * and @ have special meaning when in double quotes (see PARAMETERS below).
==={{section category|Problems}} ! treated as event designator, even within double quotes (“)=== Example of problem:
[tyler: ~]> echo "!" -bash: !: event not found [tyler: ~]> echo -e "#\!/usr/bin/ruby\nputs 'hi'" #\!/usr/bin/ruby puts 'hi' [tyler: ~]> echo -e "#!/usr/bin/ruby\nputs 'hi'" -bash: !/usr/bin/ruby\nputs: event not found
”’Solution/workaround”’:
[tyler: ~]> echo -e '#!'"/usr/bin/ruby\nputs 'hi'" #!/usr/bin/ruby puts 'hi'
Expressed even more concisely, here is the same solution again:
[tyler: ~/dev/tyler]> echo "Hi!" -bash: !": event not found [tyler: ~/dev/tyler]> echo "Hi\!" Hi\! [tyler: ~/dev/tyler]> echo "Hi"'!' Hi! [tyler: ~/dev/tyler]> echo 'Hi!' Hi!
=={{section category|Here document strings}} (heredoc strings)== Lets you create a multi-line string of input to be given as standard input to a script or program.
> cat - line 2 > End line 1 line 2
Useful for quickly creating a new file and putting some contents in it… [I guess this doesn’t work after all. Is something like this not possible??]
> out line 2 > End > cat out line 1 line 2
Unfortunately, this can’t be used to pass multi-line command-line arguments to a program. I still haven’t found a way to do that. You might try this:
> echo 'line 1'"\n"'line 2' line 1\nline 2
but unfortunately the “\n” is not treated as a newline character. Same with when I tried that trick for svn:
> svn commit -m 'line 1'"\n"'line 2'
Echo does let you do stuff like that, with its -e option — but most programs don’t have an option like that:
> echo -e 'line 1'"\n"'line 2' line 1 line 2
=if/then/fi statements= =={{section category|Caveats|Caveat}}{{section category|Syntax}} Can’t have an empty
then block!== http://svn.tylerrick.com/public/bash/examples/if_then-cant_have_empty_block.sh
#!/bin/bash if false; then # Do nothing else echo 'Hello world!' fi
Produces a syntax error:
./test.sh: line 5: syntax error near unexpected token `else' ./test.sh: line 5: `else'
”’Workaround”’:
if false; then # Do nothing /bin/true else echo 'Hello world!' fi # outputs "Hello world!"
=for Loops= http://www.google.com/search?q=bash+for+loops To list all subdirectories of the current directory:
for dir in *; do if [ -d $dir ]; then echo $dir; fi; done
(Am I just missing something? I didn’t see any options for ls
that would make it list only directories…) To execute a command inside each subdirectory of the current directory:
for dir in *; do if [ -d $dir ]; then cd $dir; do_something; cd ..; fi; done for dir in *; do if [ -d $dir ]; then cd $dir; pwd; cd ..; fi; done
For every Rails application in your ‘projects’ directory, run the tyler_svn_configure balloon:
~/projects/ > for dir in *; do if [ -d $dir ]; then echo; echo $dir; cd $dir; ruby -ropen-uri -e 'eval(open("http://balloon.hobix.com/tyler_svn_configure").read)'; cd ..; fi; done
http://tldp.org/LDP/abs/html/loops1.html ==Numerical==
> for i in `seq 1 3`; do \ > echo $i > done 1 2 3
> i=1; for x in a b c d; do \ > echo "$i. $x" > let i+=1 > done
=Command completion= Just press tab. You can set up custom completion with the complete
command.
FIGNORE A colon-separated list of suffixes to ignore when performing filename completion (see READLINE below). A filename whose suffix matches one of the entries in FIGNORE is excluded from the list of matched filenames. A sample value is ".o:~" (Quoting is needed when assigning a value to this variable, which contains tildes).
=if / ifneq / fi / tests / conditions= …
Templates used on this page:
Return to Bash.