Bash: Difference between revisions
No edit summary |
|||
(40 intermediate revisions by one other user not shown) | |||
Line 7: | Line 7: | ||
<pre> | <pre> | ||
name="Francesco" | name="Francesco" | ||
echo Hello there name | |||
echo Hello there $name | echo Hello there $name | ||
</pre> | </pre> | ||
Unlike most scripting languages, Bash is not forgiving of extra spaces and gets confused if you add them. Notice also how unlike most programming languages, in Bash text is text first, and interpreted as an expression by exception. It may be helpful to think of the ''$'' as meaning ''substitute'' the value. | |||
The use of curly braces around the name is optional, but is helpful to sometimes mark the end of a name if necessary. | The use of curly braces around the name is optional, but is helpful to sometimes mark the end of a name if necessary. | ||
Line 21: | Line 22: | ||
</pre> | </pre> | ||
There are useful special forms of variable | There are useful special forms of variable substitution in Bash: | ||
{| class="wikitable" | {| class="wikitable" | ||
| ${name:-Joe} || ''Return a default value if the variable is undefined'' <br /> If name exists and isn't null, return its value; otherwise, return 'Joe'. || | | ${name:-Joe} || ''Return a default value if the variable is undefined'' <br /> If name exists and isn't null, return its value; otherwise, return 'Joe'. || | ||
|- | |||
| ${name:offset}<br>${name:offset:length} || ''Substring'' <br /> String starting from offset, up to ''length'' chars. Length can be omitted in which case you get the rest of the text. A negative offset is relative to the end (-1 means last character). || | |||
|- | |||
| ${#name} || ''Length'' <br /> Returns the length of a variable. || | |||
|- | |- | ||
| ${name:=Joe} || ''Sets a default value if the variable is undefined'' <br /> Return the value of name if it exists and isn't null; otherwise, set it to 'Joe' and return that. || | | ${name:=Joe} || ''Sets a default value if the variable is undefined'' <br /> Return the value of name if it exists and isn't null; otherwise, set it to 'Joe' and return that. || | ||
Line 45: | Line 50: | ||
| ${variable%%pattern} || Delete pattern \from end (longest match) || | | ${variable%%pattern} || Delete pattern \from end (longest match) || | ||
|- | |- | ||
|} | |||
=== Strip a filename extension === | |||
<source lang="bash"> | |||
filename=$1 | |||
base=${filename%.*} | |||
</source> | |||
== Arithmetic == | |||
You can do some basic arithmetic in the Bash. Note that all match is whole-number based -- doing maths with fractional numbers requires a different scripting language (like Python!)... but for basics, Bash is fine. | |||
<pre> | |||
echo $((1+2)) | |||
echo $((243-800)) | |||
echo $((10/3)) | |||
echo $((10*234)) | |||
</pre> | |||
Note that when using variables, you just need the outer $. | |||
<pre> | |||
echo $((x+1)) | |||
echo $((x*17)) | |||
</pre> | |||
See also: [http://tldp.org/LDP/abs/html/dblparens.html] | |||
== Command Substitution == | |||
Command substitution is very powerful, allowing you to run a command and capture the ''result'' in a variable, to then use in another command. There are two forms for doing this, $() and "backticks". | |||
<source lang="bash"> | |||
Hey there $(whoami). | |||
</source> | |||
Backticks (angled-backward single quotes -- find them on your keyboard!) also work: | |||
<source lang="bash"> | |||
today=`date +%A` | |||
echo Hello, today is $today | |||
</source> | |||
== Loops == | |||
=== New style === | |||
<source lang="bash"> | |||
for i in {1..20} | |||
do | |||
echo counting $i | |||
done | |||
</source> | |||
<source lang="bash"> | |||
for i in {1..20..2} | |||
do | |||
echo counting by 2 : $i | |||
done | |||
</source> | |||
Source: https://www.cyberciti.biz/faq/bash-for-loop/ | |||
=== C-style counting loops === | |||
Bash supports C-style counting loops, example: | |||
<source lang="bash"> | |||
for ((i=0; i<10; i++)) | |||
do | |||
echo $i | |||
done | |||
</source> | |||
In this compact notation, the loop is determined by a description contained in double-parentheses with 3 parts separated by semi-colons: | |||
for ((initialize; check; increment)) | |||
where: | |||
# ''Initialize'': Done once before starting the loop, i=0 means use the variable named ''i'', and start at 0. | |||
# ''Check'': Check this after each loop and stop when it's not true, i<10 means keep looping as long as i is smaller than 10. | |||
# ''Increment'': Do this at the end of each loop, i++ makes i go up by one each time. Note this actually happens ''before'' the ''check'' condition is tried. | |||
=== Iteration on a list === | |||
A for loop can be a way to ''consider the possibilities'' of a list of things. The code placed ''inside'' the "body" of the loop gets performed for each of the things in the list of possibilities. A loop is the same as repeatedly setting the given variable name and performing the code inside the loop, for ''each'' value in the list ''one after the other''. | |||
<source lang="bash"> | |||
for n in bob carol ted alice | |||
do | |||
echo $n | |||
done | |||
</source> | |||
Technically, a for loop is the same as assigning a variable (you provide the name) to each value in the list in turn, and each time running the code inside the loop. If we were to "unwrap the loop" it would look like this: | |||
Some variations of the above using a variable, and the contents of a file for the list of possibilities, both would produce the same output as above. | |||
<source lang="bash"> | |||
names="bob carol ted alice" | |||
for n in $names | |||
do | |||
echo $n | |||
done | |||
for n in $(cat names.txt) | |||
do | |||
echo $n | |||
done | |||
</source> | |||
A ''nested loop'' allows you to consider all possible 'combinations'. | |||
<source lang="bash"> | |||
for n1 in $names | |||
do | |||
for n2 in $names | |||
do | |||
echo $n1 and $n2 | |||
done | |||
done | |||
</source> | |||
would produce the output: | |||
<source lang="bash"> | |||
bob and bob | |||
bob and carol | |||
bob and ted | |||
bob and alice | |||
carol and bob | |||
carol and carol | |||
carol and ted | |||
carol and alice | |||
ted and bob | |||
ted and carol | |||
ted and ted | |||
ted and alice | |||
alice and bob | |||
alice and carol | |||
alice and ted | |||
alice and alice | |||
</source> | |||
=== Looping over filenames === | |||
<source lang="bash"> | |||
for x in *.jpg | |||
do | |||
echo $x | |||
done | |||
</source> | |||
=== Inifinte loops === | |||
while true | |||
do | |||
echo Stop this crazy thing!!! | |||
done | |||
=== While loops === | |||
A while loop repeats a block of code as long as the test condition is true. | |||
Using the read command, you can use a while loop to do something with the text of stdin, line by line (nb: line is just a variable name, it could be ''anything'')... | |||
<source lang="bash"> | |||
while read line | |||
do | |||
echo $line | |||
done | |||
</source> | |||
You can also use a while loop to count... (nb: the spaces ''inside'' the brackets are important) | |||
<source lang="bash"> | |||
x=0 | |||
while [ $x -lt 10 ] | |||
do | |||
echo and a $x... | |||
x=$((x+1)) | |||
done | |||
</source> | |||
== If-Then-Else Braches == | |||
If-then is a fundamental control structure for a computer program. Virtually every procedural (how-to) programming language will contain an if-then statement. | |||
In an 'if-then' structure, a test 'condition' is given which the computer first evaluates (checks) to either true or false. If the condition is true, the program runs the code listed after the 'then'. | |||
In Bash, an if-then looks like: | |||
<source lang="bash"> | |||
if [ $name = "fred" ] | |||
then | |||
echo Hi there Fred, long time no see! | |||
fi | |||
</source> | |||
Notice how the if "block" ends with the word "fi". (If spelled backwards, nerd humor ;). | |||
Often, an 'else' clause is included with code to run when the condition is "false". | |||
<source lang="bash"> | |||
if [ $name = "fred" ] | |||
then | |||
echo Hi there Fred, long time no see! | |||
else | |||
echo Do I know you? | |||
fi | |||
</source> | |||
You can check other conditions using "elif", just add as many as you need: | |||
<source lang="bash"> | |||
read name | |||
if [ $name = "fred" ] | |||
then | |||
echo Hi there Fred, long time no see! | |||
elif [ $name = "ethel" ] | |||
then | |||
echo Hey Ethel, whatz cookin? | |||
elif [ $name = "desi" ] | |||
then | |||
echo Babalu! | |||
else | |||
echo Do I know you? | |||
fi | |||
echo bye bye | |||
</source> | |||
If-then is sometimes called a branch or branching statement. Notice that in terms of how the program "flows" and if-then-else structure creates a literal fork in the road, with *only one* road followed, never more than one. | |||
read name | |||
{| class="wikitable" | |||
| $name = "fred" ? || $name = "ethel" ? || $name = "desi" ? || else... | |||
|- | |||
| echo Hi there Fred, long time no see! || echo Hey Ethel, what's cookin? || echo Babalu! || echo Do I know you? | |||
|} | |||
echo bye bye | |||
* [http://tldp.org/LDP/abs/html/fto.html File Test operators] | |||
== | == Functions == | ||
You can think of defining a function as adding a new word to a programming languages vocabulary. In a BASH script, when you define a new function, the name of the that function becomes like a new command-line program that you can call just like any other. Note the two styles of defining a function: | |||
- | |||
<source lang="bash"> | |||
function greet { | |||
echo hello | |||
} | |||
goodbye () { | |||
echo bye | |||
} | |||
pwd | |||
greet | |||
echo foo | |||
goodbye | |||
</source> | |||
Note that 'defining' a function doesn't have any immediate effect when the program runs. It's only once the function gets "called" (the functions name is used as a command, in the last 4 lines of the code above) that the code inside the function gets put into action. | |||
== Resources == | == Resources == | ||
* [https://wiki.bash-hackers.org/ BASH hackers wiki] | |||
* [https://www.blockloop.io/mastering-bash-and-terminal Mastering BASH and Terminal] With specifics for both Mac OS and Linux (2017) | |||
* [http://www-128.ibm.com/developerworks/aix/library/au-unix-commandline/index.html "Speaking UNIX" on IBM's developerWorks (more general UNIX command line intro)] | * [http://www-128.ibm.com/developerworks/aix/library/au-unix-commandline/index.html "Speaking UNIX" on IBM's developerWorks (more general UNIX command line intro)] | ||
Line 79: | Line 330: | ||
* http://tldp.org/LDP/abs/html/ | * http://tldp.org/LDP/abs/html/ | ||
== | ==See also== | ||
[[ | * [[File permissions]] | ||
Latest revision as of 16:59, 30 October 2023
Bash is the program that is the command line itself. BASH stands for the "Bourne-Again" Shell, the default shell for Linux and Mac OS X (Bourne-again in reference an original UNIX shell written by Stephen Bourne; BASH is a free software rewrite, part of the GNU project).
BASH scripts are, in the simplest form, just a sequence of command line commands saved in a file (or files). In this way, you can save a complicated series of steps in a single file (or BASH script). Using variables, you can turn a script into a tool that can, for instance, be applied to different input files, or perform an image transformation to a variable degree.
Variables
name="Francesco" echo Hello there name echo Hello there $name
Unlike most scripting languages, Bash is not forgiving of extra spaces and gets confused if you add them. Notice also how unlike most programming languages, in Bash text is text first, and interpreted as an expression by exception. It may be helpful to think of the $ as meaning substitute the value.
The use of curly braces around the name is optional, but is helpful to sometimes mark the end of a name if necessary.
name=Michael echo Hello there $name! echo $name123 echo ${name}123
There are useful special forms of variable substitution in Bash:
${name:-Joe} | Return a default value if the variable is undefined If name exists and isn't null, return its value; otherwise, return 'Joe'. |
|
${name:offset} ${name:offset:length} |
Substring String starting from offset, up to length chars. Length can be omitted in which case you get the rest of the text. A negative offset is relative to the end (-1 means last character). |
|
${#name} | Length Returns the length of a variable. |
|
${name:=Joe} | Sets a default value if the variable is undefined Return the value of name if it exists and isn't null; otherwise, set it to 'Joe' and return that. |
|
${name:+value} | Test for a variable being set Return the value if name is defined |
|
${name:?message} | Catches errors from a variable being undefined Return the value of name if it exists and isn't null; otherwise, prints the message and stops the script (though not guaranteed to stop -- depends on shell?) |
"Pattern-strippers" (with ShellWildcards, note that these are different from a *Regular Expression*)
${variable#pattern} | Delete pattern \from start (smallest match) | |
${variable##pattern} | Delete pattern \from start (longest match) | |
${variable%pattern} | Delete pattern \from end (smallest match) | |
${variable%%pattern} | Delete pattern \from end (longest match) |
Strip a filename extension
filename=$1
base=${filename%.*}
Arithmetic
You can do some basic arithmetic in the Bash. Note that all match is whole-number based -- doing maths with fractional numbers requires a different scripting language (like Python!)... but for basics, Bash is fine.
echo $((1+2)) echo $((243-800)) echo $((10/3)) echo $((10*234))
Note that when using variables, you just need the outer $.
echo $((x+1)) echo $((x*17))
See also: [1]
Command Substitution
Command substitution is very powerful, allowing you to run a command and capture the result in a variable, to then use in another command. There are two forms for doing this, $() and "backticks".
Hey there $(whoami).
Backticks (angled-backward single quotes -- find them on your keyboard!) also work:
today=`date +%A`
echo Hello, today is $today
Loops
New style
for i in {1..20}
do
echo counting $i
done
for i in {1..20..2}
do
echo counting by 2 : $i
done
Source: https://www.cyberciti.biz/faq/bash-for-loop/
C-style counting loops
Bash supports C-style counting loops, example:
for ((i=0; i<10; i++))
do
echo $i
done
In this compact notation, the loop is determined by a description contained in double-parentheses with 3 parts separated by semi-colons:
for ((initialize; check; increment))
where:
- Initialize: Done once before starting the loop, i=0 means use the variable named i, and start at 0.
- Check: Check this after each loop and stop when it's not true, i<10 means keep looping as long as i is smaller than 10.
- Increment: Do this at the end of each loop, i++ makes i go up by one each time. Note this actually happens before the check condition is tried.
Iteration on a list
A for loop can be a way to consider the possibilities of a list of things. The code placed inside the "body" of the loop gets performed for each of the things in the list of possibilities. A loop is the same as repeatedly setting the given variable name and performing the code inside the loop, for each value in the list one after the other.
for n in bob carol ted alice
do
echo $n
done
Technically, a for loop is the same as assigning a variable (you provide the name) to each value in the list in turn, and each time running the code inside the loop. If we were to "unwrap the loop" it would look like this:
Some variations of the above using a variable, and the contents of a file for the list of possibilities, both would produce the same output as above.
names="bob carol ted alice"
for n in $names
do
echo $n
done
for n in $(cat names.txt)
do
echo $n
done
A nested loop allows you to consider all possible 'combinations'.
for n1 in $names
do
for n2 in $names
do
echo $n1 and $n2
done
done
would produce the output:
bob and bob
bob and carol
bob and ted
bob and alice
carol and bob
carol and carol
carol and ted
carol and alice
ted and bob
ted and carol
ted and ted
ted and alice
alice and bob
alice and carol
alice and ted
alice and alice
Looping over filenames
for x in *.jpg
do
echo $x
done
Inifinte loops
while true do echo Stop this crazy thing!!! done
While loops
A while loop repeats a block of code as long as the test condition is true.
Using the read command, you can use a while loop to do something with the text of stdin, line by line (nb: line is just a variable name, it could be anything)...
while read line
do
echo $line
done
You can also use a while loop to count... (nb: the spaces inside the brackets are important)
x=0
while [ $x -lt 10 ]
do
echo and a $x...
x=$((x+1))
done
If-Then-Else Braches
If-then is a fundamental control structure for a computer program. Virtually every procedural (how-to) programming language will contain an if-then statement.
In an 'if-then' structure, a test 'condition' is given which the computer first evaluates (checks) to either true or false. If the condition is true, the program runs the code listed after the 'then'.
In Bash, an if-then looks like:
if [ $name = "fred" ]
then
echo Hi there Fred, long time no see!
fi
Notice how the if "block" ends with the word "fi". (If spelled backwards, nerd humor ;).
Often, an 'else' clause is included with code to run when the condition is "false".
if [ $name = "fred" ]
then
echo Hi there Fred, long time no see!
else
echo Do I know you?
fi
You can check other conditions using "elif", just add as many as you need:
read name
if [ $name = "fred" ]
then
echo Hi there Fred, long time no see!
elif [ $name = "ethel" ]
then
echo Hey Ethel, whatz cookin?
elif [ $name = "desi" ]
then
echo Babalu!
else
echo Do I know you?
fi
echo bye bye
If-then is sometimes called a branch or branching statement. Notice that in terms of how the program "flows" and if-then-else structure creates a literal fork in the road, with *only one* road followed, never more than one.
read name
$name = "fred" ? | $name = "ethel" ? | $name = "desi" ? | else... |
echo Hi there Fred, long time no see! | echo Hey Ethel, what's cookin? | echo Babalu! | echo Do I know you? |
echo bye bye
Functions
You can think of defining a function as adding a new word to a programming languages vocabulary. In a BASH script, when you define a new function, the name of the that function becomes like a new command-line program that you can call just like any other. Note the two styles of defining a function: -
function greet {
echo hello
}
goodbye () {
echo bye
}
pwd
greet
echo foo
goodbye
Note that 'defining' a function doesn't have any immediate effect when the program runs. It's only once the function gets "called" (the functions name is used as a command, in the last 4 lines of the code above) that the code inside the function gets put into action.
Resources
- BASH hackers wiki
- Mastering BASH and Terminal With specifics for both Mac OS and Linux (2017)
- "Speaking UNIX" on IBM's developerWorks (more general UNIX command line intro)
Other tutorials for BASH scripting:
- http://www.gentoo.org/doc/en/articles/bash-by-example-p1.xml
- http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO.html
- http://tldp.org/LDP/abs/html/