Book Image

Linux Shell Scripting Essentials

Book Image

Linux Shell Scripting Essentials

Overview of this book

Table of Contents (15 chapters)
Linux Shell Scripting Essentials
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface
Index

Shell expansions


While working with shell, we perform a lot of similar and repetitive tasks. For example, in the current directory, there are 100 files but we are interested only in shell script whose file extension is .sh. We can execute following command to view only shell script files in current directory:

$ ls *.sh

This will show all the files ending with .sh. An interesting take away from here is the * wildcard. It means a match list of files whose name can be anything and that ends with .sh.

Shell expands all wildcard patterns. A list of the latest wildcard patterns are as follows:

  • ~ (Tilde)

  • * (Asterisk)

  • ? (Question mark)

  • [ ] (Square brackets)

  • { } (Curly brackets)

To explain shell expansion for different wildcards, we will create a test folder in our home directory using the mkdir command containing different files mentioned as follows:

$ mkdir  ~/test && cd ~/test
$ touch a ab foo bar hello moo foo.c bar.c moo.c hello.txt foo.txt bar.sh hello.sh moo.sh

The touch command creates an empty file if it doesn't exist. If a file exists, then the file timestamp changes:

$ ls
a  ab  bar  bar.c  bar.sh  foo  foo.c  foo.txt  hello  hello.sh  hello.txt  moo  moo.c  moo.sh

Running the preceding commands will create a test directory, and inside test directory creates files given as parameter to the touch command.

~ (Tilde)

~ (Tilde) gets expanded by bash when it is present at the beginning of an unquoted string. The expansion depends upon what tilde-prefix is used. Tilde prefixes are characters until the first unquoted (/) slash. Some of the bash expansions are as follows:

  • ~: This is the user's home directory; the value is set in the $HOME variable

  • ~user_name: This is the home directory of the user's user_name

  • ~user_name/file_name: This is the file/directory file_name in the user's user_name home directory

  • ~/file_name: This is the file/directory file_name in the home directory that is $HOME/file_name

  • ~+: This is the current working directory; the value is set in the $PWD variable

  • ~-: This is the old or last working directory; the value is set in the $OLDPWD variable

  • ~+/file_name: This is the file/directory file_name in the current directory that is $PWD/file_name

  • ~-/file_name: This is the file/directory file_name in the old/last working directory that is $OLDPWD/file_name

* (Asterisk)

It matches zero or more characters. Take a test directory as an example:

  • Display all files as follows:

    $ ls *
    a  ab  bar  bar.c  bar.sh  foo  foo.c  foo.txt  hello  hello.sh  hello.txt  moo  moo.c  moo.sh
    
  • Display the C source files as follows:

    $ ls *.c
    bar.c  foo.c  moo.c
    
  • Display files that have a in its name, as follows:

    $ ls *a*
    a  ab  bar  bar.c  bar.sh
    
  • Deleting files with an extension .txt as follows:

    $ rm *.txt
    $ ls
    a  ab  bar  bar.c  bar.sh  foo  foo.c  hello  hello.sh  moo  moo.c  moo.sh
    

? (Question mark)

It matches any single character: ? (single question mark will match a single character), ?? (double question mark matches any two characters), and so on. Take a test directory as an example:

$ touch a ab foo bar hello moo foo.c bar.c moo.c hello.txt foo.txt bar.sh hello.sh moo.sh

This will recreate files that were removed during the previous example, and also update the access and modification time of the existing files:

  • Get files whose name length is irrespective of what the extension file has:

    $ ls ??
    ab
    
  • Get files whose name length is 2 or 5:

    $ ls ?? ?????
    ab  bar.c  foo.c  hello  moo.c
    
  • Delete files whose name is four characters long:

    $ rm ????
    rm: cannot remove '????': No such file or directory
    This error is because there is no file name with 4 character
    
  • Move files to the /tmp directory whose name is at least three characters long:

    $ mv ???* /tmp
    $ ls
    a ab
    

We see only two files in the test directory because the rest of the files were of the length 3 or more.

[ ] (Square brackets)

Square brackets match any character from the characters mentioned inside the square brackets. Characters can be specified as a word or range.

A range of characters can be specified using - (hyphen). For example:

  • [a-c]: This matches a, b, or c

  • [a-z]: This matches any character from a to z

  • [A-Z]: This matches any character from A to Z

  • [0-9]: This matches any character from 0 to 9

Take a test directory as an example and recreate files in a test directory:

$ touch a ab foo bar hello moo foo.c bar.c moo.c hello.txt foo.txt bar.sh hello.sh moo.sh

Get files whose name starts with a, b, c, or d with the following command:

$ ls [a-d]*
a  ab  bar  bar.c  bar.sh

Get files whose name starts with any letter and ends with a letter o or h, with the following command:

$  ls [a-zA-Z]*[oh]
foo  hello  hello.sh  moo  moo.sh

Get files that have at least the letter o twice in its name, with the following command:

$ ls *[o]*[o]*
foo  foo.c  foo.txt  moo  moo.c  moo.sh

[!characters] (Exclamation mark) is used to match a character that is not part of a charter set mentioned inside square brackets.

Get files that don't have a number in its name, with the following command:

$  ls [!0-9]*
a  ab  bar  bar.c  bar.sh  foo  foo.c  foo.txt  hello  hello.sh  hello.txt  moo  moo.c  moo.sh

{ } (Curly brackets)

It creates multiple wildcard patterns to match. A brace expression may contain either a comma-separated list of strings, a range, or a single character.

A range can be specified by using the following:

  • {a..z}: This matches all the charterer from a to z

  • {0..6}: This matches numbers 0, 1, 2, 3, 4, 5 and 6

Take a test directory as an example and recreate files in the test directory:

$ touch a ab foo bar hello moo foo.c bar.c moo.c hello.txt foo.txt bar.sh hello.sh moo.sh

Get files that have the file extension .sh or .c, with the following command:

$ ls {*.sh,*.c}
bar.c  bar.sh  foo.c  hello.sh  moo.c  moo.sh

Copy bar.c to bar.html by using the following command:

$ cp bar{.c,.cpp}  # Expands to cp bar.c bar.cpp
$ ls bar.*
bar.c  bar.cpp  bar.sh

Print the number from 1 to 50 by using the following command:

$ echo {1..50}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50

Create 10 files that start with hello and has an extension .cpp:

$ touch hello{0..9}.cpp
$ ls *.cpp
hello0.cpp  hello1.cpp  hello2.cpp  hello3.cpp  hello4.cpp  hello5.cpp  hello6.cpp  hello7.cpp  hello8.cpp  hello9.cpp

To avoid shell expansion of a wildcard, use backslash (\) or write a string within a single quote (' ').