The second beta has just come out. For those of you following along with my Getting Ready For Ubuntu 10.04 series, you can get the latest version here:
http://www.ubuntu.com/testing/lucid/beta2
Thursday, April 8, 2010
New Features In Bash Version 4.x - Part 2
Now that we have covered some of the minor improvements found in bash 4.x, we will begin looking at the more significant new features focusing on changes in the way bash 4.x handles expansions.
Zero-Padded Brace Expansion
As you may recall, bash supports an interesting expansion called brace expansion. With it, you can rapidly create sequences. This is often useful for creating large numbers of file names or directories in a hurry. Here is an example similar to one in my book:
bshotts@twin7: ~$ mkdir -p foo/{2007..2010}-{1..12}
bshotts@twin7: ~$ ls foo
2007-1 2007-4 2008-1 2008-4 2009-1 2009-4 2010-1 2010-4
2007-10 2007-5 2008-10 2008-5 2009-10 2009-5 2010-10 2010-5
2007-11 2007-6 2008-11 2008-6 2009-11 2009-6 2010-11 2010-6
2007-12 2007-7 2008-12 2008-7 2009-12 2009-7 2010-12 2010-7
2007-2 2007-8 2008-2 2008-8 2009-2 2009-8 2010-2 2010-8
2007-3 2007-9 2008-3 2008-9 2009-3 2009-9 2010-3 2010-9
This command creates a series of directories for the years 2007-2010 and the months 1-12. You'll notice however that the list of directories does not sort very well. This is because the month portion of the directory name lacks a leading zero for the months 1-9. To create this directory series with correct names, we would have to do this:
bshotts@twin7:~$ rm -r foo
bshotts@twin7:~$ mkdir -p foo/{2007..2010}-0{1..9} foo/{2007..2010}-{10..12}
bshotts@twin7:~$ ls foo
2007-01 2007-07 2008-01 2008-07 2009-01 2009-07 2010-01 2010-07
2007-02 2007-08 2008-02 2008-08 2009-02 2009-08 2010-02 2010-08
2007-03 2007-09 2008-03 2008-09 2009-03 2009-09 2010-03 2010-09
2007-04 2007-10 2008-04 2008-10 2009-04 2009-10 2010-04 2010-10
2007-05 2007-11 2008-05 2008-11 2009-05 2009-11 2010-05 2010-11
2007-06 2007-12 2008-06 2008-12 2009-06 2009-12 2010-06 2010-12
That's what we want. but we had to basically double the size of our command to do it.
bash version 4.x now allows you prefix zeros to the values being expanded to get zero-padding when the expansion is performed. For example:
No leading zeros:
bshotts@twin7:~$ echo {1..20}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
One leading zero:
bshotts@twin7:~$ echo {01..20}
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20
Two leading zeros:
bshotts@twin7:~$ echo {001..20}
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020
...and so on.
With this new feature, our directory creating command can be reduced to this:
bshotts@twin7:~$ rm -r foo
bshotts@twin7:~$ mkdir -p foo/{2007..2010}-{01..12}
bshotts@twin7:~$ ls foo
2007-01 2007-07 2008-01 2008-07 2009-01 2009-07 2010-01 2010-07
2007-02 2007-08 2008-02 2008-08 2009-02 2009-08 2010-02 2010-08
2007-03 2007-09 2008-03 2008-09 2009-03 2009-09 2010-03 2010-09
2007-04 2007-10 2008-04 2008-10 2009-04 2009-10 2010-04 2010-10
2007-05 2007-11 2008-05 2008-11 2009-05 2009-11 2010-05 2010-11
2007-06 2007-12 2008-06 2008-12 2009-06 2009-12 2010-06 2010-12
Case Conversion
One of the big themes in bash 4.x is upper/lower-case conversion of strings. bash adds four new parameter expansions and two new options to the declare command to support it.
So what is case conversion good for? Aside from the obvious aesthetic value, it has an important role in programming. Let's consider the case of a database look-up. Imagine that a user has entered a string into a data input field that we want to look up in a database. It's possible the user will enter the value in all upper-case letters or lower-case letters or a combination of both. We certainly don't want to populate our database with every possible permutation of upper and lower case spellings. What to do?
A common approach to this problem is to normalize the user's input. That is, convert it into a standardized form before we attempt the database look-up. We can do this by converting all of the characters in the user's input to either lower or upper-case and ensure that the database entries are normalized the same way.
The declare command in bash 4.x can be used to normalize strings to either upper or lower-case. Using declare, we can force a variable to always contain the desired format no matter what is assigned to it:
#!/bin/bash
# ul-declare: demonstrate case conversion via declare
declare -u upper
declare -l lower
if [[ $1 ]]; then
upper="$1"
lower="$1"
echo $upper
echo $lower
fi
In the above script, we use declare to create two variables, upper and lower. We assign the value of the first command line argument (positional parameter 1) to each of the variables and then display them on the screen:
bshotts@twin7:~$ ul-declare aBc
ABC
abc
As we can see, the command line argument ("aBc") has been normalized.
bash version 4.x also includes four new parameter expansions that perform upper/lower-case conversion:
Here is a script that demonstrates these expansions:
#!/bin/bash
# ul-param - demonstrate case conversion via parameter expansion
if [[ $1 ]]; then
echo ${1,,}
echo ${1,}
echo ${1^^}
echo ${1^}
fi
Here is the script in action:
bshotts@twin7:~$ ul-param aBc
abc
aBc
ABC
ABc
Again, we process the first command line argument and output the four variations supported by the new parameter expansions. While this script uses the first positional parameter, parameter my be any string, variable, or string expression.
Further Reading
The Linux Command Line
Zero-Padded Brace Expansion
As you may recall, bash supports an interesting expansion called brace expansion. With it, you can rapidly create sequences. This is often useful for creating large numbers of file names or directories in a hurry. Here is an example similar to one in my book:
bshotts@twin7: ~$ mkdir -p foo/{2007..2010}-{1..12}
bshotts@twin7: ~$ ls foo
2007-1 2007-4 2008-1 2008-4 2009-1 2009-4 2010-1 2010-4
2007-10 2007-5 2008-10 2008-5 2009-10 2009-5 2010-10 2010-5
2007-11 2007-6 2008-11 2008-6 2009-11 2009-6 2010-11 2010-6
2007-12 2007-7 2008-12 2008-7 2009-12 2009-7 2010-12 2010-7
2007-2 2007-8 2008-2 2008-8 2009-2 2009-8 2010-2 2010-8
2007-3 2007-9 2008-3 2008-9 2009-3 2009-9 2010-3 2010-9
This command creates a series of directories for the years 2007-2010 and the months 1-12. You'll notice however that the list of directories does not sort very well. This is because the month portion of the directory name lacks a leading zero for the months 1-9. To create this directory series with correct names, we would have to do this:
bshotts@twin7:~$ rm -r foo
bshotts@twin7:~$ mkdir -p foo/{2007..2010}-0{1..9} foo/{2007..2010}-{10..12}
bshotts@twin7:~$ ls foo
2007-01 2007-07 2008-01 2008-07 2009-01 2009-07 2010-01 2010-07
2007-02 2007-08 2008-02 2008-08 2009-02 2009-08 2010-02 2010-08
2007-03 2007-09 2008-03 2008-09 2009-03 2009-09 2010-03 2010-09
2007-04 2007-10 2008-04 2008-10 2009-04 2009-10 2010-04 2010-10
2007-05 2007-11 2008-05 2008-11 2009-05 2009-11 2010-05 2010-11
2007-06 2007-12 2008-06 2008-12 2009-06 2009-12 2010-06 2010-12
That's what we want. but we had to basically double the size of our command to do it.
bash version 4.x now allows you prefix zeros to the values being expanded to get zero-padding when the expansion is performed. For example:
No leading zeros:
bshotts@twin7:~$ echo {1..20}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
One leading zero:
bshotts@twin7:~$ echo {01..20}
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20
Two leading zeros:
bshotts@twin7:~$ echo {001..20}
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020
...and so on.
With this new feature, our directory creating command can be reduced to this:
bshotts@twin7:~$ rm -r foo
bshotts@twin7:~$ mkdir -p foo/{2007..2010}-{01..12}
bshotts@twin7:~$ ls foo
2007-01 2007-07 2008-01 2008-07 2009-01 2009-07 2010-01 2010-07
2007-02 2007-08 2008-02 2008-08 2009-02 2009-08 2010-02 2010-08
2007-03 2007-09 2008-03 2008-09 2009-03 2009-09 2010-03 2010-09
2007-04 2007-10 2008-04 2008-10 2009-04 2009-10 2010-04 2010-10
2007-05 2007-11 2008-05 2008-11 2009-05 2009-11 2010-05 2010-11
2007-06 2007-12 2008-06 2008-12 2009-06 2009-12 2010-06 2010-12
Case Conversion
One of the big themes in bash 4.x is upper/lower-case conversion of strings. bash adds four new parameter expansions and two new options to the declare command to support it.
So what is case conversion good for? Aside from the obvious aesthetic value, it has an important role in programming. Let's consider the case of a database look-up. Imagine that a user has entered a string into a data input field that we want to look up in a database. It's possible the user will enter the value in all upper-case letters or lower-case letters or a combination of both. We certainly don't want to populate our database with every possible permutation of upper and lower case spellings. What to do?
A common approach to this problem is to normalize the user's input. That is, convert it into a standardized form before we attempt the database look-up. We can do this by converting all of the characters in the user's input to either lower or upper-case and ensure that the database entries are normalized the same way.
The declare command in bash 4.x can be used to normalize strings to either upper or lower-case. Using declare, we can force a variable to always contain the desired format no matter what is assigned to it:
#!/bin/bash
# ul-declare: demonstrate case conversion via declare
declare -u upper
declare -l lower
if [[ $1 ]]; then
upper="$1"
lower="$1"
echo $upper
echo $lower
fi
In the above script, we use declare to create two variables, upper and lower. We assign the value of the first command line argument (positional parameter 1) to each of the variables and then display them on the screen:
bshotts@twin7:~$ ul-declare aBc
ABC
abc
As we can see, the command line argument ("aBc") has been normalized.
bash version 4.x also includes four new parameter expansions that perform upper/lower-case conversion:
| Format | Result |
| ${parameter,,} | Expand the value of parameter into all lower-case. |
| ${parameter,} | Expand the value of parameter changing only the first character to lower-case. |
| ${parameter^^} | Expand the value of parameter into all upper-case letters. |
| ${parameter^} | Expand the value of parameter changing on the first character to upper-case (capitalization). |
Here is a script that demonstrates these expansions:
#!/bin/bash
# ul-param - demonstrate case conversion via parameter expansion
if [[ $1 ]]; then
echo ${1,,}
echo ${1,}
echo ${1^^}
echo ${1^}
fi
Here is the script in action:
bshotts@twin7:~$ ul-param aBc
abc
aBc
ABC
ABc
Again, we process the first command line argument and output the four variations supported by the new parameter expansions. While this script uses the first positional parameter, parameter my be any string, variable, or string expression.
Further Reading
The Linux Command Line
- Chapter 8 (covers expansions)
- http://www.gnu.org/software/bash/manual/bashref.html#Brace-Expansion
- http://www.gnu.org/software/bash/manual/bashref.html#Shell-Parameter-Expansion
- http://www.gnu.org/software/bash/manual/bashref.html#Bash-Builtins
- http://bash-hackers.org/wiki/doku.php/syntax/expansion/brace
- http://bash-hackers.org/wiki/doku.php/syntax/pe#case_modification
Tuesday, April 6, 2010
New Features In Bash Version 4.x - Part 1
As I mention in the introduction to The Linux Command Line, the command line is a long lasting skill. It's quite possible that a script that you wrote ten years ago still works perfectly well today. But even so, every few years the GNU Project releases a new version of bash. While I was writing the book, version 3.2 was the predominate version found in Linux distributions. In February of 2009 however a new major version of bash (4.0) appeared and it began to show up in distributions last fall. Today the current version of bash is 4.1 and it, too, is beginning to show up in distributions such as Ubuntu 10.04 and (I presume, since I haven't checked yet) Fedora 13.
So what's new in bash? A bunch of things, though most of them tend to be rather small. In this series we will look at features that, I feel, are of the most use to ordinary shell users starting with a couple of the small ones.
Finding Your Version
How do you know if you are using the latest, greatest bash? By issuing a command of course:
me@linuxbox: ~$ echo $BASH_VERSION
4.1.2(1)-release
bash maintains a shell variable called BASH_VERSION that always contains the version number of the shell in use. The example above is from my Ubuntu 10.04 test machine and it dutifully reveals that we are running bash version 4.1.2.
Better help
The help command, which is used to display documentation for the shell's builtin commands, got some much needed attention in the new version of bash. The command has some new options and the help text itself has been reformatted and improved. For example, here is the result of the help cd command in bash 3.2:
bshotts@twin2:~$ help cd
cd: cd [-L|-P] [dir]
Change the current directory to DIR. The variable $HOME is the
default DIR. The variable CDPATH defines the search path for
the directory containing DIR. Alternative directory names in CDPATH
are separated by a colon (:). A null directory name is the same as
the current directory, i.e. `.'. If DIR begins with a slash (/),
then CDPATH is not used. If the directory is not found, and the
shell option `cdable_vars' is set, then try the word as a variable
name. If that variable has a value, then cd to the value of that
variable. The -P option says to use the physical directory structure
instead of following symbolic links; the -L option forces symbolic links
to be followed.
The same command in bash 4.1:
bshotts@twin7:~$ help cd
cd: cd [-L|-P] [dir]
Change the shell working directory.
Change the current directory to DIR. The default DIR is the value of the
HOME shell variable.
The variable CDPATH defines the search path for the directory containing
DIR. Alternative directory names in CDPATH are separated by a colon (:).
A null directory name is the same as the current directory. If DIR begins
with a slash (/), then CDPATH is not used.
If the directory is not found, and the shell option `cdable_vars' is set,
the word is assumed to be a variable name. If that variable has a value,
its value is used for DIR.
Options:
-L force symbolic links to be followed
-P use the physical directory structure without following symbolic
links
The default is to follow symbolic links, as if `-L' were specified.
Exit Status:
Returns 0 if the directory is changed; non-zero otherwise.
As you can see, the output is more "man page-like" than the previous version, as well as better written. help also includes two new options, -d which displays a short description of the command and the -m option which displays the help text in full man page format.
New Redirections
It is now possible to combine both standard output and standard error from a command and append it to a file using this form:
command &>> file
Likewise, it is possible to pipe the combined output streams using this:
command1 |& command2
where the standard output and standard error of command1 is piped into the standard input of command2. This form may be used in place of the traditional form:
command1 2>&1 | command2
Further Reading
Here are some change summaries for the 4.x version of bash:
Other installments in this series: 1 2 3 4
So what's new in bash? A bunch of things, though most of them tend to be rather small. In this series we will look at features that, I feel, are of the most use to ordinary shell users starting with a couple of the small ones.
Finding Your Version
How do you know if you are using the latest, greatest bash? By issuing a command of course:
me@linuxbox: ~$ echo $BASH_VERSION
4.1.2(1)-release
bash maintains a shell variable called BASH_VERSION that always contains the version number of the shell in use. The example above is from my Ubuntu 10.04 test machine and it dutifully reveals that we are running bash version 4.1.2.
Better help
The help command, which is used to display documentation for the shell's builtin commands, got some much needed attention in the new version of bash. The command has some new options and the help text itself has been reformatted and improved. For example, here is the result of the help cd command in bash 3.2:
bshotts@twin2:~$ help cd
cd: cd [-L|-P] [dir]
Change the current directory to DIR. The variable $HOME is the
default DIR. The variable CDPATH defines the search path for
the directory containing DIR. Alternative directory names in CDPATH
are separated by a colon (:). A null directory name is the same as
the current directory, i.e. `.'. If DIR begins with a slash (/),
then CDPATH is not used. If the directory is not found, and the
shell option `cdable_vars' is set, then try the word as a variable
name. If that variable has a value, then cd to the value of that
variable. The -P option says to use the physical directory structure
instead of following symbolic links; the -L option forces symbolic links
to be followed.
The same command in bash 4.1:
bshotts@twin7:~$ help cd
cd: cd [-L|-P] [dir]
Change the shell working directory.
Change the current directory to DIR. The default DIR is the value of the
HOME shell variable.
The variable CDPATH defines the search path for the directory containing
DIR. Alternative directory names in CDPATH are separated by a colon (:).
A null directory name is the same as the current directory. If DIR begins
with a slash (/), then CDPATH is not used.
If the directory is not found, and the shell option `cdable_vars' is set,
the word is assumed to be a variable name. If that variable has a value,
its value is used for DIR.
Options:
-L force symbolic links to be followed
-P use the physical directory structure without following symbolic
links
The default is to follow symbolic links, as if `-L' were specified.
Exit Status:
Returns 0 if the directory is changed; non-zero otherwise.
As you can see, the output is more "man page-like" than the previous version, as well as better written. help also includes two new options, -d which displays a short description of the command and the -m option which displays the help text in full man page format.
New Redirections
It is now possible to combine both standard output and standard error from a command and append it to a file using this form:
command &>> file
Likewise, it is possible to pipe the combined output streams using this:
command1 |& command2
where the standard output and standard error of command1 is piped into the standard input of command2. This form may be used in place of the traditional form:
command1 2>&1 | command2
Further Reading
Here are some change summaries for the 4.x version of bash:
Other installments in this series: 1 2 3 4
Thursday, April 1, 2010
Script: average
A few weeks ago, I was cruising the Ubuntu forums and came across a question from a poster who wanted to find the average of a series of floating-point numbers. The numbers were extracted from some other command and were output in a column. He wanted a command line incantation that would take the column of numbers and return the average. Several people answered this query with clever one-line solutions, however I thought that this problem would be a good task for a script. Using a script, one could have a solution that was a little more robust and general purpose. I wrote the following script, presented here with line numbers:
1 #!/bin/bash
2
3 # average - calculate the average of a series of numbers
4
5 # handle cmd line option
6 if [[ $1 ]]; then
7 case $1 in
8 -s|--scale) scale=$2 ;;
9 *) echo "usage: average [-s scale]" >&2
10 exit 1 ;;
11 esac
12 fi
13
14 # construct instruction stream for bc
15 c=0
16 { echo "t = 0; scale = 2"
17 [[ $scale ]] && echo "scale = $scale"
18 while read value; do
19
20 # only process valid numbers
21 if [[ $value =~ ^[-+]?[0-9]*\.?[0-9]+$ ]]; then
22 echo "t += $value"
23 ((++c))
24 fi
25 done
26
27 # make sure we don't divide by zero
28 ((c)) && echo "t / $c"
29 } | bc
This script takes a series of numbers from standard input and prints the result. It is invoked as follows:
average -s scale < file_of_numbers
where scale is an integer containing the desired number of decimal places in the result and file_of_numbers is a file containing the series of number we desire to average. If scale is not specified, then the default value of 2 is used.
To demonstrate the script, we will calculate the average size of the programs in the /usr/bin directory:
me@linuxbox:~$ stat --format "%s" /usr/bin/* | average
81766.66
The basic idea behind this script is that it uses the bc arbitrary precision calculator program to figure out the average. We need to use something like bc, because arithmetic expansion in the shell can only handle integer math.
To perform our calculation, we need to construct a series of instructions and pipe them into bc. This task comprises the bulk of our script. In order to do something that complicated, we employ a shell feature known as a group command. Starting with line 16 and ending with line 29 we capture all of the standard output and consolidate it into a single stream. That is, all of the standard output produced by the commands on lines 16-29 is treated as though it is a single command and piped into bc on line 29.
We'll look at our group command piece by piece. As you know, an average is calculated by adding up a series of numbers and dividing the sum by the number of entries. In our case, the number of entries is stored in the variable c and the sum is stored (within bc) in the variable t. We start our group command (line 16) by passing some initial values to bc. We set the initial value of the bc variable t to zero and the value of scale to our default value of two (the default scale of bc is zero).
On line 17, we evaluate the scale variable to see if the command line option was used and if so, pass that new value to bc.
Next, we start a while loop that reads entries from our standard input. Each iteration of the loop causes the next entry in the series to be assigned to the variable value.
Lines 20-24 are interesting. Here we test to see if the string contained in value is actually a valid floating point number. To do this, we employ a regular expression that will only match if the number is properly formatted. The regular expression says, to match, value may start with a plus or minus sign, followed by zero or more numerals, followed by an optional decimal point, and ending with one or more numerals.. If value passes this test, an instruction is inserted into the stream telling bc to add value to t (line 22) and we increment c (line 23), otherwise value is ignored.
After all of the numbers have been read from standard input, it's time to perform the calculation, First, we test to see that we actually processed some numbers. If we did not, then c would equal zero and the resulting calculation would cause a "division by zero" error, so we test the value of c and only if it is not equal to zero we insert the final instruction for bc.
This script would make a good starting point for a series of statistical programs. The most significant design weakness of the script as written is that it fails to check that the value supplied to the scale option is really an integer. That's an improvement I will leave to my faithful readers...
Further Reading
The following man pages:
1 #!/bin/bash
2
3 # average - calculate the average of a series of numbers
4
5 # handle cmd line option
6 if [[ $1 ]]; then
7 case $1 in
8 -s|--scale) scale=$2 ;;
9 *) echo "usage: average [-s scale]" >&2
10 exit 1 ;;
11 esac
12 fi
13
14 # construct instruction stream for bc
15 c=0
16 { echo "t = 0; scale = 2"
17 [[ $scale ]] && echo "scale = $scale"
18 while read value; do
19
20 # only process valid numbers
21 if [[ $value =~ ^[-+]?[0-9]*\.?[0-9]+$ ]]; then
22 echo "t += $value"
23 ((++c))
24 fi
25 done
26
27 # make sure we don't divide by zero
28 ((c)) && echo "t / $c"
29 } | bc
This script takes a series of numbers from standard input and prints the result. It is invoked as follows:
average -s scale < file_of_numbers
where scale is an integer containing the desired number of decimal places in the result and file_of_numbers is a file containing the series of number we desire to average. If scale is not specified, then the default value of 2 is used.
To demonstrate the script, we will calculate the average size of the programs in the /usr/bin directory:
me@linuxbox:~$ stat --format "%s" /usr/bin/* | average
81766.66
The basic idea behind this script is that it uses the bc arbitrary precision calculator program to figure out the average. We need to use something like bc, because arithmetic expansion in the shell can only handle integer math.
To perform our calculation, we need to construct a series of instructions and pipe them into bc. This task comprises the bulk of our script. In order to do something that complicated, we employ a shell feature known as a group command. Starting with line 16 and ending with line 29 we capture all of the standard output and consolidate it into a single stream. That is, all of the standard output produced by the commands on lines 16-29 is treated as though it is a single command and piped into bc on line 29.
We'll look at our group command piece by piece. As you know, an average is calculated by adding up a series of numbers and dividing the sum by the number of entries. In our case, the number of entries is stored in the variable c and the sum is stored (within bc) in the variable t. We start our group command (line 16) by passing some initial values to bc. We set the initial value of the bc variable t to zero and the value of scale to our default value of two (the default scale of bc is zero).
On line 17, we evaluate the scale variable to see if the command line option was used and if so, pass that new value to bc.
Next, we start a while loop that reads entries from our standard input. Each iteration of the loop causes the next entry in the series to be assigned to the variable value.
Lines 20-24 are interesting. Here we test to see if the string contained in value is actually a valid floating point number. To do this, we employ a regular expression that will only match if the number is properly formatted. The regular expression says, to match, value may start with a plus or minus sign, followed by zero or more numerals, followed by an optional decimal point, and ending with one or more numerals.. If value passes this test, an instruction is inserted into the stream telling bc to add value to t (line 22) and we increment c (line 23), otherwise value is ignored.
After all of the numbers have been read from standard input, it's time to perform the calculation, First, we test to see that we actually processed some numbers. If we did not, then c would equal zero and the resulting calculation would cause a "division by zero" error, so we test the value of c and only if it is not equal to zero we insert the final instruction for bc.
This script would make a good starting point for a series of statistical programs. The most significant design weakness of the script as written is that it fails to check that the value supplied to the scale option is really an integer. That's an improvement I will leave to my faithful readers...
Further Reading
The following man pages:
- bc
- bash (the "Compound Commands" section, covers group commands and the [[]] and (()) compound commands)
- Chapter 20 (regular expressions)
- Chapter 28 (if command, [[]] and (()) compound commands and && and || control operators)
- Chapter 29 (the read command)
- Chapter 30 (while loops)
- Chapter 35 (arithmetic expressions and expansion, bc program)
- Chapter 33 (positional parameters)
- Chapter 37 (group commands)
Tuesday, March 30, 2010
Site News: LinuxCommand.org Turns 10!
LinuxCommand.org is 10 years old! The site first went live in March 2000. Since then I've had about 3.2 million visitors (at least according to the statistics at SourceForge where I'm hosted), received many kind emails from my readers, written a book, distributed a lot of scripts, and been mirrored all around the world.
In the coming year, I hope to update the tutorials on the site. Much of the text, believe it or not, dates back to the beginning of the site, another testament to the enduring value of learning the command line. But even so, the tutorials are getting a little outdated and my own knowledge has grown considerably over the last ten years as well.
As you may have noticed, this blog has been pretty busy and I have settled into a routine of posting twice a week (on Tuesdays and Thursdays) and I have many more topics in mind to cover. And there is always the book to improve. I've even toyed with writing another one...
Anyway, I want to thank everyone for their kind words of encouragement and support. I know I don't always respond to each email that I receive, but I do try. Speaking of support, you can support the work here at LinuxCommand.org by purchasing your very own printed copy of my book. I've donated money to a number of free and open source software projects over the years and continue to "pay for my software" by producing this site and performing software testing on projects that interest me.
Thanks to everyone for ten great years!
Further Reading
A look at LinuxCommand.org over the years, courtesy of the Wayback Machine:
The traffic history of LinuxCommand.org:
In the coming year, I hope to update the tutorials on the site. Much of the text, believe it or not, dates back to the beginning of the site, another testament to the enduring value of learning the command line. But even so, the tutorials are getting a little outdated and my own knowledge has grown considerably over the last ten years as well.
As you may have noticed, this blog has been pretty busy and I have settled into a routine of posting twice a week (on Tuesdays and Thursdays) and I have many more topics in mind to cover. And there is always the book to improve. I've even toyed with writing another one...
Anyway, I want to thank everyone for their kind words of encouragement and support. I know I don't always respond to each email that I receive, but I do try. Speaking of support, you can support the work here at LinuxCommand.org by purchasing your very own printed copy of my book. I've donated money to a number of free and open source software projects over the years and continue to "pay for my software" by producing this site and performing software testing on projects that interest me.
Thanks to everyone for ten great years!
Further Reading
A look at LinuxCommand.org over the years, courtesy of the Wayback Machine:
The traffic history of LinuxCommand.org:
Subscribe to:
Posts (Atom)
