From charlesreid1

No edit summary
 
(11 intermediate revisions by the same user not shown)
Line 1: Line 1:
Bash Quick Reference: [[Bash/Quick]]
Bash Quick Prototype: [[Bash/Prototype]]
= Bash Guide =
= Bash Guide =


Line 5: Line 9:
Setting the default shell: http://www.unix.com/shell-programming-scripting/32664-how-change-default-shell-linux.html
Setting the default shell: http://www.unix.com/shell-programming-scripting/32664-how-change-default-shell-linux.html


[[Image:OSXTerminalSettings.png|none|250px|frame|You can set the default shell in Mac's Terminal by going settings and specifying the login shell.]]
[[Image:OSXTerminalSettings.png|none|250px|frame|You can set the default shell in Mac's Terminal by going to <code>Terminal > Preferences</code> and specifying the login shell.]]


== Startup Process ==
== Startup Process ==


The order for sourcing dot files in bash is as follows:
{{Main|Dot files}}
 
== Dot Files ==
 
= Bash Scripting =
 
== Looping ==
 
Looping in bash is really simple, and convenient - you can use other unix commands (most obviously "ls") to create lists, and then loop over each element of those lists.  For example, if I want to print out the name of every file in my home directory (granted, not very useful, but this is just an example), I can do this:
 
<pre>


'''Once per login session:'''
for i in `/bin/ls -1 $HOME`; do
    echo $i
done


1. source /etc/profile - this contains the system-wide profile settings; these are only executed once per login session, and should define any bash variables that need to be defined for everyone; examples include the ${PATH}, the ${MANPATH}, the machine name, and/or enabling things that are not bash-specific (remember the [[Csh]] shell will also source .profile).
</pre>


2. source ~/.profile - this contains user-specific profile settings; these settings are the same as above, except they are variables that should only be set for one user.  The user's ${PATH} and ${MANPATH} variables, in particular, should be set here.
To do some serious bash looping kung-fu, check out [[Xargs]].


See my [[dotprofile]]
==Bash Loop One-Liner: Seq and Destroy==


3. source ~/.bash_profile - (?) This one I'm not so sure about, it's not a "standard" bash file to be sourced.  Plus its role is a little vague.  I use this to define settings for my bash history.
Sometimes, you want to do a bash loop, but you want to do it on the fly, so you don't have to fire up your text editor and make a bash script.


See my [[dotbash_profile]]
[[Seq]] to the rescue!
 
The seq command is a way of creating very simple numerical sequences:
 
<pre>
$ seq 1 10
1
2
3
4
5
6
7
8
9
10
</pre>
 
But seq has some other features that make it very handy (see the [[Seq]] page for a full list of examples).
 
Seq can be very easily combined with bash to create one-line for loops.
 
Let's pose a simple scenario: say you've imported a bunch of photos from your camera, and their naming convention looks like this:got a lit of photos like this:
 
{{Scroll box
|content=
<pre>
IMG_0000.jpg
IMG_0001.jpg
IMG_0002.jpg
IMG_0003.jpg
IMG_0004.jpg
IMG_0005.jpg
IMG_0006.jpg
IMG_0007.jpg
IMG_0008.jpg
IMG_0009.jpg
IMG_0010.jpg
IMG_0011.jpg
IMG_0012.jpg
IMG_0013.jpg
IMG_0014.jpg
IMG_0015.jpg
IMG_0016.jpg
IMG_0017.jpg
IMG_0018.jpg
IMG_0019.jpg
IMG_0020.jpg
IMG_0021.jpg
IMG_0022.jpg
IMG_0023.jpg
IMG_0024.jpg
IMG_0025.jpg
IMG_0026.jpg
IMG_0027.jpg
IMG_0028.jpg
IMG_0029.jpg
IMG_0030.jpg
IMG_0031.jpg
IMG_0032.jpg
IMG_0033.jpg
IMG_0034.jpg
IMG_0035.jpg
IMG_0036.jpg
IMG_0037.jpg
IMG_0038.jpg
IMG_0039.jpg
IMG_0040.jpg
IMG_0041.jpg
IMG_0042.jpg
IMG_0043.jpg
IMG_0044.jpg
IMG_0045.jpg
IMG_0046.jpg
IMG_0047.jpg
IMG_0048.jpg
IMG_0049.jpg
IMG_0050.jpg
</pre>
}}
 
Now, let's say we want to move some photos to another folder, but we only want to move the odd-numbered photographs starting at 10 and ending at 40.
 
We can whip up a quick seq command that'll give us even numbers from 10 to 40:
 
<pre>
$ seq 10 2 40
</pre>
 
But we need the whole thing to be formatted into a comma-separated list, so we can feed it to a bash command, like <code>mv {this,that} the_other/.</code>. So let's use the -s flag:
 
<pre>
$ seq -s, 10 2 40
10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,
</pre>
 
Now we can use bash's backticks to plop that command in the middle of another mv command:
 
<pre>
$ mv directory1/IMG_00{`seq -s, 10 2 40`}.jpg directory2/.
</pre>
 
which unfolds to:
 
{{Scroll box
|content=
<pre>
mv directory1/IMG_0010.jpg directory2/.
mv directory1/IMG_0012.jpg directory2/.
mv directory1/IMG_0014.jpg directory2/.
mv directory1/IMG_0016.jpg directory2/.
mv directory1/IMG_0018.jpg directory2/.
mv directory1/IMG_0020.jpg directory2/.
mv directory1/IMG_0022.jpg directory2/.
mv directory1/IMG_0024.jpg directory2/.
mv directory1/IMG_0026.jpg directory2/.
mv directory1/IMG_0028.jpg directory2/.
mv directory1/IMG_0030.jpg directory2/.
mv directory1/IMG_0032.jpg directory2/.
mv directory1/IMG_0034.jpg directory2/.
mv directory1/IMG_0036.jpg directory2/.
mv directory1/IMG_0038.jpg directory2/.
mv directory1/IMG_0040.jpg directory2/.
</pre>
}}


4. source /etc/bashrc - sources the system-wide bashrc file.  This will define the default appearance of the command prompt, any aliases, or any settings related to the bash history that should apply to every user.
Voila!


5. source ~/.bashrc - sources the user-specific bashrc file. This contains user-specific settings for the prompt, aliases, functions, etc.
But what if the range of file numbers strides 100? If you wanted to go from 80 to 120, you would end up with mismatching zero-padding. To get around this, you could either force seq to output all numbers with a fixed width (using the -w flag), or you could get more fancy by specifying a printf (print format) string for seq to use when printing each number (via the -f flag in seq).


See my [[dotbashrc]]
Let's repeat the example, but this time using the printf approach. First, we want to print a 4-digit number that is zero-padded, meaning our printf string is going to be <code>%04g</code>. Now the seq command looks like:


== Dot Files ==
<pre>
$ seq -s, -f'%04g' 80 2 120
0080,0082,0084,0086,0088,0090,0092,0094,0096,0098,0100,0102,0104,0106,0108,0110,0112,0114,0116,0118,0120,
</pre>


= Bash Scripting =
(Note we could have also used the printf string <code>'IMG_%04g.jpg'</code> to make things a little more compact.)


== Looping ==
Now we can feed that directly to the mv command:


Looping in bash is really simple, and convenient - you can use other unix commands (most obviously "ls") to create lists, and then loop over each element of those lists. For example, if I want to print out the name of every file in my home directory (granted, not very useful, but this is just an example), I can do this:
<pre>
$ mv directory1/IMG_{`seq -s, -f'%04g' 80 2 120`}.jpg directory2/.
</pre>


<source lang="bash">
which unfolds into the set of bash commands:


for i in `/bin/ls -1 $HOME`; do
{{Scroll box
    echo $i
|content=
done
<pre>
mv directory1/IMG_0080.jpg directory2/.
mv directory1/IMG_0082.jpg directory2/.
mv directory1/IMG_0084.jpg directory2/.
mv directory1/IMG_0086.jpg directory2/.
mv directory1/IMG_0088.jpg directory2/.
mv directory1/IMG_0090.jpg directory2/.
mv directory1/IMG_0092.jpg directory2/.
mv directory1/IMG_0094.jpg directory2/.
mv directory1/IMG_0096.jpg directory2/.
mv directory1/IMG_0098.jpg directory2/.
mv directory1/IMG_0100.jpg directory2/.
mv directory1/IMG_0102.jpg directory2/.
mv directory1/IMG_0104.jpg directory2/.
mv directory1/IMG_0106.jpg directory2/.
mv directory1/IMG_0108.jpg directory2/.
mv directory1/IMG_0110.jpg directory2/.
mv directory1/IMG_0112.jpg directory2/.
mv directory1/IMG_0114.jpg directory2/.
mv directory1/IMG_0116.jpg directory2/.
mv directory1/IMG_0118.jpg directory2/.
mv directory1/IMG_0120.jpg directory2/.
</pre>
}}


</source>
Voila!


To do some serious bash looping kung-fu, check out [[Xargs]].
You can find more information about seq, and how to couple it with other Unix utilities, at the [[Seq]] page on my wiki.


== Logical Operators ==
== Logical Operators ==
Line 55: Line 223:
These can be tested using a simple "if" statement.  In bash, if statements are of the form:
These can be tested using a simple "if" statement.  In bash, if statements are of the form:


<source lang="bash">
<pre>
if [[ condition ]]; then
if [[ condition ]]; then
     cmd
     cmd
Line 61: Line 229:
     cmd2
     cmd2
fi
fi
</source>
</pre>


The spaces between the brackets and the condition are essential.
The spaces between the brackets and the condition are essential.
A comprehensive list of logical condition checks is here: http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_07_01.html


===Integer Operators===
===Integer Operators===
Line 75: Line 245:
|<code>-eq</code>
|<code>-eq</code>
|returns true if arguments are equal
|returns true if arguments are equal
|<source lang="bash">
|<pre>
$ a=1; b=1; if [[ "$a" -eq "$b" ]]; then echo "true"; else echo "false"; fi
$ a=1; b=1; if [[ "$a" -eq "$b" ]]; then echo "true"; else echo "false"; fi
true
true
Line 81: Line 251:
$ a=1; b=2; if [[ "$a" -eq "$b" ]]; then echo "true"; else echo "false"; fi
$ a=1; b=2; if [[ "$a" -eq "$b" ]]; then echo "true"; else echo "false"; fi
false
false
</source>
</pre>


|-
|-
|<code>-ne</code>
|<code>-ne</code>
|returns true if arguments are not equal
|returns true if arguments are not equal
|<source lang="bash">
|<pre>
$ a=1; b=1; if [[ "$a" -ne "$b" ]]; then echo "true"; else echo "false"; fi
$ a=1; b=1; if [[ "$a" -ne "$b" ]]; then echo "true"; else echo "false"; fi
false
false
Line 92: Line 262:
$ a=1; b=2; if [[ "$a" -ne "$b" ]]; then echo "true"; else echo "false"; fi
$ a=1; b=2; if [[ "$a" -ne "$b" ]]; then echo "true"; else echo "false"; fi
true
true
</source>
</pre>


|-
|-
|<code>-gt</code>
|<code>-gt</code>
|returns true if argument 1 is greater than argument 2
|returns true if argument 1 is greater than argument 2
|<source lang="bash">
|<pre>
$ a=5; b=10; if [[ "$a" -gt "$b" ]]; then echo "true"; else echo "false"; fi
$ a=5; b=10; if [[ "$a" -gt "$b" ]]; then echo "true"; else echo "false"; fi
false
false
</source>
</pre>


|-
|-
|<code>-ge</code>
|<code>-ge</code>
|returns true if argument 1 is greater than or equal to argument 2
|returns true if argument 1 is greater than or equal to argument 2
|<source lang="bash">
|<pre>
$ a=15; b=10; if [[ "$a" -ge "$b" ]]; then echo "true"; else echo "false"; fi
$ a=15; b=10; if [[ "$a" -ge "$b" ]]; then echo "true"; else echo "false"; fi
true
true
Line 111: Line 281:
$ a=10; b=10; if [[ "$a" -ge "$b" ]]; then echo "true"; else echo "false"; fi
$ a=10; b=10; if [[ "$a" -ge "$b" ]]; then echo "true"; else echo "false"; fi
true
true
</source>
</pre>


|-
|-
|<code>-lt</code>
|<code>-lt</code>
|returns true if argument 1 less than argument 2
|returns true if argument 1 less than argument 2
|<source lang="bash">
|<pre>
$ a=5; b=10; if [[ "$a" -lt "$b" ]]; then echo "true"; else echo "false"; fi
$ a=5; b=10; if [[ "$a" -lt "$b" ]]; then echo "true"; else echo "false"; fi
true
true
</source>
</pre>


|-
|-
|<code>-le</code>
|<code>-le</code>
|returns true if argument 1 less than or equal to argument 2
|returns true if argument 1 less than or equal to argument 2
|<source lang="bash">
|<pre>
$ a=15; b=10; if [[ "$a" -le "$b" ]]; then echo "true"; else echo "false"; fi
$ a=15; b=10; if [[ "$a" -le "$b" ]]; then echo "true"; else echo "false"; fi
false
false
Line 130: Line 300:
$ a=10; b=10; if [[ "$a" -le "$b" ]]; then echo "true"; else echo "false"; fi
$ a=10; b=10; if [[ "$a" -le "$b" ]]; then echo "true"; else echo "false"; fi
true
true
</source>
</pre>


|-
|-
Line 137: Line 307:


this needs to be escaped with a \ if it occurs inside single brackets; otherwise it can appear between double bracket or between double parentheses
this needs to be escaped with a \ if it occurs inside single brackets; otherwise it can appear between double bracket or between double parentheses
|<source lang="bash">
|<pre>
$ a=10; b=10; if [ "$a" \< "$b" ]; then echo "true"; else echo "false"; fi
$ a=10; b=10; if [ "$a" \< "$b" ]; then echo "true"; else echo "false"; fi
false
false
Line 146: Line 316:
$ a=10; b=10; if (( "$a" < "$b" )); then echo "true"; else echo "false"; fi
$ a=10; b=10; if (( "$a" < "$b" )); then echo "true"; else echo "false"; fi
false
false
</source>
</pre>


|-
|-
Line 153: Line 323:


this operator needs to go inside double parentheses
this operator needs to go inside double parentheses
|<source lang="bash">
|<pre>
$ a=10; b=10; if (( "$a" <= "$b" )); then echo "true"; else echo "false"; fi
$ a=10; b=10; if (( "$a" <= "$b" )); then echo "true"; else echo "false"; fi
true
true
</source>
</pre>


|-
|-
Line 163: Line 333:


this needs to be escaped with a \ if it occurs inside single brackets; otherwise it can appear between double bracket or between double parentheses
this needs to be escaped with a \ if it occurs inside single brackets; otherwise it can appear between double bracket or between double parentheses
|<source lang="bash">
|<pre>
$ z=10; zz=1000;  
$ z=10; zz=1000;  


Line 171: Line 341:
$ if [[ zz > z ]]; then echo "true"; else echo "false"; fi
$ if [[ zz > z ]]; then echo "true"; else echo "false"; fi
true
true
</source>
</pre>


|-
|-
Line 178: Line 348:


this operator needs to go inside double parentheses
this operator needs to go inside double parentheses
|<source lang="bash">
|<pre>
$ a=50; b=10; if (( $a >= $b )); then echo "true"; else echo "false"; fi
$ a=50; b=10; if (( $a >= $b )); then echo "true"; else echo "false"; fi
true
true
</source>
</pre>


|}
|}
Line 195: Line 365:
|<code>=</code>
|<code>=</code>
|returns true if two strings are equal
|returns true if two strings are equal
|<source lang="bash">
|<pre>
$ a=foo; b=foo; if [[ "$a" = "$b" ]]; then echo "true"; else echo "false"; fi
$ a=foo; b=foo; if [[ "$a" = "$b" ]]; then echo "true"; else echo "false"; fi
true
true
Line 201: Line 371:
$ a=foo; b=bar; if [[ "$a" = "$b" ]]; then echo "true"; else echo "false"; fi
$ a=foo; b=bar; if [[ "$a" = "$b" ]]; then echo "true"; else echo "false"; fi
false
false
</source>
</pre>


|-
|-
|<code>==</code>
|<code>==</code>
|returns true if two strings are equal; equivalent to <code>=</code>
|returns true if two strings are equal; equivalent to <code>=</code>
|<source lang="bash">
|<pre>
$ a=foo; b=foo; if [[ "$a" == "$b" ]]; then echo "true"; else echo "false"; fi
$ a=foo; b=foo; if [[ "$a" == "$b" ]]; then echo "true"; else echo "false"; fi
true
true
Line 212: Line 382:
$ a=foo; b=bar; if [[ "$a" == "$b" ]]; then echo "true"; else echo "false"; fi
$ a=foo; b=bar; if [[ "$a" == "$b" ]]; then echo "true"; else echo "false"; fi
false
false
</source>
</pre>


Note the difference between quoting a string and not quoting a string:
Note the difference between quoting a string and not quoting a string:
Line 224: Line 394:
|<code>!=</code>
|<code>!=</code>
|returns true if strings are not equal
|returns true if strings are not equal
|<source lang="bash">
|<pre>
$ a=foo; b=bar; if [[ "$a" != "$b" ]]; then echo "true"; else echo "false"; fi
$ a=foo; b=bar; if [[ "$a" != "$b" ]]; then echo "true"; else echo "false"; fi
true
true
</source>
</pre>


|-
|-
|<code> < </code>
|<code> < </code>
|returns true if argument 1 is less than (alphabetically) argument 2; capitals come before non-capitals
|returns true if argument 1 is less than (alphabetically) argument 2; capitals come before non-capitals
|<source lang="bash">
|<pre>
$ a=foo; b=bar; if [[ "$a" < "$b" ]]; then echo "true"; else echo "false"; fi
$ a=foo; b=bar; if [[ "$a" < "$b" ]]; then echo "true"; else echo "false"; fi
false
false
Line 241: Line 411:
$ a=bar; b=foo; if [[ "$a" < "$b" ]]; then echo "true"; else echo "false"; fi
$ a=bar; b=foo; if [[ "$a" < "$b" ]]; then echo "true"; else echo "false"; fi
true
true
</source>
</pre>


|-
|-
|<code> > </code>
|<code> > </code>
|returns true if argument 1 is greater than (alphabetically) argument 2; capitals come before non-capitals
|returns true if argument 1 is greater than (alphabetically) argument 2; capitals come before non-capitals
|<source lang="bash">
|<pre>
$ a=foo; b=bar; if [[ "$a" > "$b" ]]; then echo "true"; else echo "false"; fi
$ a=foo; b=bar; if [[ "$a" > "$b" ]]; then echo "true"; else echo "false"; fi
true
true
Line 252: Line 422:
$ a=Foo; b=bar; if [[ "$a" > "$b" ]]; then echo "true"; else echo "false"; fi
$ a=Foo; b=bar; if [[ "$a" > "$b" ]]; then echo "true"; else echo "false"; fi
false
false
</source>
</pre>


|-
|-
|<code>-z</code>
|<code>-z</code>
|returns true if the string is null
|returns true if the string is null
|<source lang="bash">
|<pre>
$ a=""; b="foobar"; if [ -z "$a" ]; then echo "true"; else echo "false"; fi
$ a=""; b="foobar"; if [ -z "$a" ]; then echo "true"; else echo "false"; fi
true
true
Line 263: Line 433:
$ a=""; b="foobar"; if [ -z "$b" ]; then echo "true"; else echo "false"; fi
$ a=""; b="foobar"; if [ -z "$b" ]; then echo "true"; else echo "false"; fi
false
false
</source>
</pre>


|-
|-
|<code>-n</code>
|<code>-n</code>
|returns true if the string is NOT null
|returns true if the string is NOT null
|<source lang="bash">
|<pre>
$ a=""; b="foobar"; if [ -n "$a" ]; then echo "true"; else echo "false"; fi
$ a=""; b="foobar"; if [ -n "$a" ]; then echo "true"; else echo "false"; fi
false
false
Line 274: Line 444:
$ a=""; b="foobar"; if [ -n "$b" ]; then echo "true"; else echo "false"; fi
$ a=""; b="foobar"; if [ -n "$b" ]; then echo "true"; else echo "false"; fi
true
true
</source>
</pre>


|}
|}
Line 291: Line 461:
|<code>-a</code>
|<code>-a</code>
|Logical and (both conditions must be true for condition to be true)
|Logical and (both conditions must be true for condition to be true)
|<source lang="bash">
|<pre>
if [ "$expr1" -a "$expr2" ]
if [ "$expr1" -a "$expr2" ]
then
then
Line 298: Line 468:
   echo "Either expr1 or expr2 is false."
   echo "Either expr1 or expr2 is false."
fi
fi
</source>
</pre>


|-
|-
|<code>-o</code>
|<code>-o</code>
|Logical or (either condition must be true for condition to be true)
|Logical or (either condition must be true for condition to be true)
|<source lang="bash">
|<pre>
if [ "$expr1" -o "$expr2" ]
if [ "$expr1" -o "$expr2" ]
then
then
Line 310: Line 480:
   echo "Both expr1 and expr2 are false."
   echo "Both expr1 and expr2 are false."
fi
fi
</source>
</pre>


|}
|}
Line 318: Line 488:
{{Main|Bash Math#Basic Math}}
{{Main|Bash Math#Basic Math}}


== Complex Math Operators ==
==Complex Math==
 
{{Main|Bash Math#Complex Math}}
 
==Math Operators==


{{Main|Bash Math#Operators}}
{{Main|Bash Math#Operators}}
==Bash Scripts for Heavy Bash Users==
See https://github.com/alexanderepstein/Bash-Snippets
* weather
* geoip info
* currency
* encryption/decryption
* movies
* cheat - finding command options and code pieces
* taste - "find similar things to X"


=Bash Keyboard Shortcuts=
=Bash Keyboard Shortcuts=
Line 369: Line 554:
http://www.tech-recipes.com/rx/636/bash-shell-script-iterate-through-array-values/
http://www.tech-recipes.com/rx/636/bash-shell-script-iterate-through-array-values/


[[Category:Computers]]
[[Category:Programs]]


[[Category:Languages]]
=Flags=
[[Category:Unix]]
 
{{Programs}}
{{Unix Programs}}
{{Languages}}
 
[[Category:Bash]]

Latest revision as of 02:45, 30 March 2019

Bash Quick Reference: Bash/Quick

Bash Quick Prototype: Bash/Prototype

Bash Guide

Using Bash

Setting the default shell: http://www.unix.com/shell-programming-scripting/32664-how-change-default-shell-linux.html

You can set the default shell in Mac's Terminal by going to Terminal > Preferences and specifying the login shell.

Startup Process

Dot Files

Bash Scripting

Looping

Looping in bash is really simple, and convenient - you can use other unix commands (most obviously "ls") to create lists, and then loop over each element of those lists. For example, if I want to print out the name of every file in my home directory (granted, not very useful, but this is just an example), I can do this:


for i in `/bin/ls -1 $HOME`; do
    echo $i
done

To do some serious bash looping kung-fu, check out Xargs.

Bash Loop One-Liner: Seq and Destroy

Sometimes, you want to do a bash loop, but you want to do it on the fly, so you don't have to fire up your text editor and make a bash script.

Seq to the rescue!

The seq command is a way of creating very simple numerical sequences:

$ seq 1 10
1
2
3
4
5
6
7
8
9
10

But seq has some other features that make it very handy (see the Seq page for a full list of examples).

Seq can be very easily combined with bash to create one-line for loops.

Let's pose a simple scenario: say you've imported a bunch of photos from your camera, and their naming convention looks like this:got a lit of photos like this:

IMG_0000.jpg
IMG_0001.jpg
IMG_0002.jpg
IMG_0003.jpg
IMG_0004.jpg
IMG_0005.jpg
IMG_0006.jpg
IMG_0007.jpg
IMG_0008.jpg
IMG_0009.jpg
IMG_0010.jpg
IMG_0011.jpg
IMG_0012.jpg
IMG_0013.jpg
IMG_0014.jpg
IMG_0015.jpg
IMG_0016.jpg
IMG_0017.jpg
IMG_0018.jpg
IMG_0019.jpg
IMG_0020.jpg
IMG_0021.jpg
IMG_0022.jpg
IMG_0023.jpg
IMG_0024.jpg
IMG_0025.jpg
IMG_0026.jpg
IMG_0027.jpg
IMG_0028.jpg
IMG_0029.jpg
IMG_0030.jpg
IMG_0031.jpg
IMG_0032.jpg
IMG_0033.jpg
IMG_0034.jpg
IMG_0035.jpg
IMG_0036.jpg
IMG_0037.jpg
IMG_0038.jpg
IMG_0039.jpg
IMG_0040.jpg
IMG_0041.jpg
IMG_0042.jpg
IMG_0043.jpg
IMG_0044.jpg
IMG_0045.jpg
IMG_0046.jpg
IMG_0047.jpg
IMG_0048.jpg
IMG_0049.jpg
IMG_0050.jpg

Now, let's say we want to move some photos to another folder, but we only want to move the odd-numbered photographs starting at 10 and ending at 40.

We can whip up a quick seq command that'll give us even numbers from 10 to 40:

$ seq 10 2 40

But we need the whole thing to be formatted into a comma-separated list, so we can feed it to a bash command, like mv {this,that} the_other/.. So let's use the -s flag:

$ seq -s, 10 2 40
10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,

Now we can use bash's backticks to plop that command in the middle of another mv command:

$ mv directory1/IMG_00{`seq -s, 10 2 40`}.jpg directory2/.

which unfolds to:

mv directory1/IMG_0010.jpg directory2/.
mv directory1/IMG_0012.jpg directory2/.
mv directory1/IMG_0014.jpg directory2/.
mv directory1/IMG_0016.jpg directory2/.
mv directory1/IMG_0018.jpg directory2/.
mv directory1/IMG_0020.jpg directory2/.
mv directory1/IMG_0022.jpg directory2/.
mv directory1/IMG_0024.jpg directory2/.
mv directory1/IMG_0026.jpg directory2/.
mv directory1/IMG_0028.jpg directory2/.
mv directory1/IMG_0030.jpg directory2/.
mv directory1/IMG_0032.jpg directory2/.
mv directory1/IMG_0034.jpg directory2/.
mv directory1/IMG_0036.jpg directory2/.
mv directory1/IMG_0038.jpg directory2/.
mv directory1/IMG_0040.jpg directory2/.

Voila!

But what if the range of file numbers strides 100? If you wanted to go from 80 to 120, you would end up with mismatching zero-padding. To get around this, you could either force seq to output all numbers with a fixed width (using the -w flag), or you could get more fancy by specifying a printf (print format) string for seq to use when printing each number (via the -f flag in seq).

Let's repeat the example, but this time using the printf approach. First, we want to print a 4-digit number that is zero-padded, meaning our printf string is going to be %04g. Now the seq command looks like:

$ seq -s, -f'%04g' 80 2 120
0080,0082,0084,0086,0088,0090,0092,0094,0096,0098,0100,0102,0104,0106,0108,0110,0112,0114,0116,0118,0120,

(Note we could have also used the printf string 'IMG_%04g.jpg' to make things a little more compact.)

Now we can feed that directly to the mv command:

$ mv directory1/IMG_{`seq -s, -f'%04g' 80 2 120`}.jpg directory2/.

which unfolds into the set of bash commands:

mv directory1/IMG_0080.jpg directory2/.
mv directory1/IMG_0082.jpg directory2/.
mv directory1/IMG_0084.jpg directory2/.
mv directory1/IMG_0086.jpg directory2/.
mv directory1/IMG_0088.jpg directory2/.
mv directory1/IMG_0090.jpg directory2/.
mv directory1/IMG_0092.jpg directory2/.
mv directory1/IMG_0094.jpg directory2/.
mv directory1/IMG_0096.jpg directory2/.
mv directory1/IMG_0098.jpg directory2/.
mv directory1/IMG_0100.jpg directory2/.
mv directory1/IMG_0102.jpg directory2/.
mv directory1/IMG_0104.jpg directory2/.
mv directory1/IMG_0106.jpg directory2/.
mv directory1/IMG_0108.jpg directory2/.
mv directory1/IMG_0110.jpg directory2/.
mv directory1/IMG_0112.jpg directory2/.
mv directory1/IMG_0114.jpg directory2/.
mv directory1/IMG_0116.jpg directory2/.
mv directory1/IMG_0118.jpg directory2/.
mv directory1/IMG_0120.jpg directory2/.

Voila!

You can find more information about seq, and how to couple it with other Unix utilities, at the Seq page on my wiki.

Logical Operators

NOTE: the use of double brackets for logical condition checks is highly recommended.

There are several logical operators available for checking conditions in bash.

These can be tested using a simple "if" statement. In bash, if statements are of the form:

if [[ condition ]]; then
    cmd
else
    cmd2
fi

The spaces between the brackets and the condition are essential.

A comprehensive list of logical condition checks is here: http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_07_01.html

Integer Operators

Operator Meaning Example
-eq returns true if arguments are equal
$ a=1; b=1; if [[ "$a" -eq "$b" ]]; then echo "true"; else echo "false"; fi
true

$ a=1; b=2; if [[ "$a" -eq "$b" ]]; then echo "true"; else echo "false"; fi
false
-ne returns true if arguments are not equal
$ a=1; b=1; if [[ "$a" -ne "$b" ]]; then echo "true"; else echo "false"; fi
false

$ a=1; b=2; if [[ "$a" -ne "$b" ]]; then echo "true"; else echo "false"; fi
true
-gt returns true if argument 1 is greater than argument 2
$ a=5; b=10; if [[ "$a" -gt "$b" ]]; then echo "true"; else echo "false"; fi
false
-ge returns true if argument 1 is greater than or equal to argument 2
$ a=15; b=10; if [[ "$a" -ge "$b" ]]; then echo "true"; else echo "false"; fi
true

$ a=10; b=10; if [[ "$a" -ge "$b" ]]; then echo "true"; else echo "false"; fi
true
-lt returns true if argument 1 less than argument 2
$ a=5; b=10; if [[ "$a" -lt "$b" ]]; then echo "true"; else echo "false"; fi
true
-le returns true if argument 1 less than or equal to argument 2
$ a=15; b=10; if [[ "$a" -le "$b" ]]; then echo "true"; else echo "false"; fi
false

$ a=10; b=10; if [[ "$a" -le "$b" ]]; then echo "true"; else echo "false"; fi
true
\< returns true if argument 1 less than argument 2

this needs to be escaped with a \ if it occurs inside single brackets; otherwise it can appear between double bracket or between double parentheses

$ a=10; b=10; if [ "$a" \< "$b" ]; then echo "true"; else echo "false"; fi
false

$ a=10; b=10; if [[ "$a" < "$b" ]]; then echo "true"; else echo "false"; fi
false

$ a=10; b=10; if (( "$a" < "$b" )); then echo "true"; else echo "false"; fi
false
<= returns true if argument 1 less than or equal to argument 2

this operator needs to go inside double parentheses

$ a=10; b=10; if (( "$a" <= "$b" )); then echo "true"; else echo "false"; fi
true
> returns true if argument 1 greater than argument 2

this needs to be escaped with a \ if it occurs inside single brackets; otherwise it can appear between double bracket or between double parentheses

$ z=10; zz=1000; 

$ if [ zz \> z ]; then echo "true"; else echo "false"; fi
true

$ if [[ zz > z ]]; then echo "true"; else echo "false"; fi
true
>= returns true if argument 1 greater than or equal to argument 2

this operator needs to go inside double parentheses

$ a=50; b=10; if (( $a >= $b )); then echo "true"; else echo "false"; fi
true

String Operators

Operator Meaning Example
= returns true if two strings are equal
$ a=foo; b=foo; if [[ "$a" = "$b" ]]; then echo "true"; else echo "false"; fi
true

$ a=foo; b=bar; if [[ "$a" = "$b" ]]; then echo "true"; else echo "false"; fi
false
== returns true if two strings are equal; equivalent to =
$ a=foo; b=foo; if [[ "$a" == "$b" ]]; then echo "true"; else echo "false"; fi
true

$ a=foo; b=bar; if [[ "$a" == "$b" ]]; then echo "true"; else echo "false"; fi
false

Note the difference between quoting a string and not quoting a string:

[[ $a ==  b*  ]] # returns true if $a starts with b (pattern matching)
[[ $a == "b*" ]] # returns true if $a is literally equal to b* (literal matching)
!= returns true if strings are not equal
$ a=foo; b=bar; if [[ "$a" != "$b" ]]; then echo "true"; else echo "false"; fi
true
< returns true if argument 1 is less than (alphabetically) argument 2; capitals come before non-capitals
$ a=foo; b=bar; if [[ "$a" < "$b" ]]; then echo "true"; else echo "false"; fi
false

$ a=Foo; b=bar; if [[ "$a" < "$b" ]]; then echo "true"; else echo "false"; fi
true

$ a=bar; b=foo; if [[ "$a" < "$b" ]]; then echo "true"; else echo "false"; fi
true
> returns true if argument 1 is greater than (alphabetically) argument 2; capitals come before non-capitals
$ a=foo; b=bar; if [[ "$a" > "$b" ]]; then echo "true"; else echo "false"; fi
true

$ a=Foo; b=bar; if [[ "$a" > "$b" ]]; then echo "true"; else echo "false"; fi
false
-z returns true if the string is null
$ a=""; b="foobar"; if [ -z "$a" ]; then echo "true"; else echo "false"; fi
true

$ a=""; b="foobar"; if [ -z "$b" ]; then echo "true"; else echo "false"; fi
false
-n returns true if the string is NOT null
$ a=""; b="foobar"; if [ -n "$a" ]; then echo "true"; else echo "false"; fi
false

$ a=""; b="foobar"; if [ -n "$b" ]; then echo "true"; else echo "false"; fi
true


Compound Operators

You can combine logical operators using and/or operators:

Operator Meaning Example
-a Logical and (both conditions must be true for condition to be true)
if [ "$expr1" -a "$expr2" ]
then
  echo "Both expr1 and expr2 are true."
else
  echo "Either expr1 or expr2 is false."
fi
-o Logical or (either condition must be true for condition to be true)
if [ "$expr1" -o "$expr2" ]
then
  echo "Either expr1 or expr2 is true."
else
  echo "Both expr1 and expr2 are false."
fi

Basic Math

Complex Math

Math Operators

Bash Scripts for Heavy Bash Users

See https://github.com/alexanderepstein/Bash-Snippets

  • weather
  • geoip info
  • currency
  • encryption/decryption
  • movies
  • cheat - finding command options and code pieces
  • taste - "find similar things to X"

Bash Keyboard Shortcuts

Editing Shortcuts

The following are keyboard shortcuts for easy navigation/editing of commands that are on the Bash command line.

Movement

  • C-a - Move to beginning of line
  • C-e - Move to end of line


  • M-f - Move forward 1 word
  • M-b - Move backward 1 word


  • C-f - Move forward 1 character
  • C-b - Move backward 1 character

Cutting and Pasting

  • C-k - kill (cut) from cursor to end of line
  • C-w - kill (cut) from cursor to previous whitespace
  • C-y - yank (paste) previously killed text at cursor

Uncategorized

  • C-L - clear screen, reprint current line at top
  • C-u - undo last edit
  • C-d - delete character under cursor

References

Floating point math in the shell:

http://www.novell.com/coolsolutions/tools/17043.html

Fast bash math:

http://www.bytemycode.com/snippets/snippet/350/

Bash script iterate through array of values

http://www.tech-recipes.com/rx/636/bash-shell-script-iterate-through-array-values/


Flags