The Introduction of Shell Script

该教程介绍了Shell脚本的基础知识,包括代码段的显示方式、命令行输入的表示、变量的使用(包括作用域和未声明变量的处理)、通配符的运用以及如何避免性能问题。还讲解了循环结构(如for和while循环)和条件测试用法,展示了如何在脚本中进行条件判断。
摘要由CSDN通过智能技术生成

Typographical Conventions Used in This Tutorial

Code segments and script output will be displayed as monospaced text.
Command-line entries will be preceded by the Dollar sign ($). If your prompt is different, enter the command:

PS1="$ " ; export PS1
[maxwell@oracle-db-19c shell_projects]$ PS1="$ "; export PS1
$ 
$ 
$ echo '#!/bin/sh' > my-script.sh
$ echo 'echo Hello World' >> my-script.sh
$ chmod 775 my-script.sh
$ ./my-script.sh
Hello World
$ ls -ltr
total 12
-rw-rw-r--. 1 maxwell maxwell 244 Mar  7 19:57 sorted_data.sh
-rw-rw-r--. 1 maxwell maxwell  84 Mar  7 20:00 source_data.csv
-rwxrwxr-x. 1 maxwell maxwell  27 Mar  9 13:09 my-script.sh
$ 

2. Philosophy

  • The speed at which an interpreted program will run as compared to a C program, or even an interpreted Perl program.
  • Since it is easy to write a simple batch-job type shell script, there are a lot of poor quality shell scripts around.

One weakness in many shell scripts is lines such as:

cat /tmp/myfile | grep "mystring"

which would run much faster as:

grep "mystring" /tmp/myfile

3. Variables 

$ 
$ vi var.sh
$ chmod 775 var.sh
$ ./var.sh
Hello World
$ cat var.sh
#!/bin/sh
MY_MESSAGE="Hello World"
echo $MY_MESSAGE
$ 
$ vim var2.sh
$ chmod 775 var2.sh
$ ./var2.sh
What is your name?
Maxwell 
Hello Maxwell - hope you're well.
$ cat var2.sh
#!/bin/sh
echo What is your name?
read MY_NAME
echo "Hello $MY_NAME - hope you're well."
$ 

4.Scope of Variables

Variables in the Bourne shell do not have to be declared, as they do in languages like C. But if you try to read an undeclared variable, the result is the empty string. You get no warnings or errors. This can cause some subtle bugs - if you assign
MY_OBFUSCATED_VARIABLE=Hello
and then
echo $MY_OSFUCATED_VARIABLE
Then you will get nothing (as the second OBFUSCATED is mis-spelled).

$ 
$ vim myvar2.sh
$ chmod a+rx myvar2.sh
$ ./myvar2.sh
MYVAR is: 
MYVAR is: hi there
$ cat myvar2.sh
#!/bin/sh
echo "MYVAR is: $MYVAR"
MYVAR="hi there"
echo "MYVAR is: $MYVAR"
$ 

$ 
$ MYVAR=hello
$ ./myvar2.sh  
MYVAR is: 
MYVAR is: hi there
$ 
$ 

We need to export the variable for it to be inherited by another program - including a shell script.

$ 
$ MYVAR=hello
$ ./myvar2.sh  
MYVAR is: 
MYVAR is: hi there
$ 
$ 
$ export MYVAR
$ ./myvar2.sh 
MYVAR is: hello
MYVAR is: hi there
$ 

Once the shell script exits, its environment is destroyed. But MYVAR keeps its value of hello within your interactive shell.
In order to receive environment changes back from the script, we must source the script - this effectively runs the script within our own interactive shell, instead of spawning another shell to run it.
We can source a script via the "." (dot) command:

$ 
$ MYVAR=hello
$ echo $MYVAR
hello
$
$ . ./myvar2.sh
MYVAR is: hello
MYVAR is: hi there
$ echo $MYVAR
hi there
$ 
$ 
$ vim user.sh      
$ chmod 775 user.sh
$ ./user.sh        
What is your name?
Maxwell
Hello Maxwell
I will create you a file called Maxwell_file
$ cat user.sh
#!/bin/sh
echo "What is your name?"
read USER_NAME
echo "Hello $USER_NAME"
echo "I will create you a file called ${USER_NAME}_file"
touch "${USER_NAME}_file"
$ 

5. Wildcards(通配符)

$ cp /tmp/a/* /tmp/b/
$ cp /tmp/a/*.txt /tmp/b/
$ cp /tmp/a/*.html /tmp/b/


$ mv *.txt *.bak

6. Escape Characters

Certain characters are significant to the shell; we have seen, for example, that the use of double quotes (") characters affect how spaces and TAB characters are treated, for example:

$ 
$ echo Hello     World
Hello World
$ echo "Hello    World"
Hello    World
$ 

$ 
$ echo Hello     World
Hello World
$ echo "Hello    World"
Hello    World
$ 
$ 
$ 
$ echo "Hello \"World\""
Hello "World"
$ 
$ echo "Hello " Word ""
Hello  Word 
$ 

In the first example, * is expanded to mean all files in the current directory.
In the second example, *txt means all files ending in txt.
In the third, we put the * in double quotes, and it is interpreted literally.
In the fourth example, the same applies, but we have appended txt to the string.

$ ls -ltr
total 32
-rw-rw-r--. 1 maxwell maxwell 244 Mar  7 19:57 sorted_data.sh
-rw-rw-r--. 1 maxwell maxwell  84 Mar  7 20:00 source_data.csv
-rwxrwxr-x. 1 maxwell maxwell  92 Mar  9 13:15 my-script.sh
-rwxrwxr-x. 1 maxwell maxwell 255 Mar  9 14:32 first2.sh
-rwxrwxr-x. 1 maxwell maxwell  52 Mar  9 14:36 var.sh
-rwxrwxr-x. 1 maxwell maxwell  91 Mar  9 14:42 var2.sh
-rwxrwxr-x. 1 maxwell maxwell  75 Mar  9 14:56 myvar2.sh
-rwxrwxr-x. 1 maxwell maxwell 158 Mar  9 15:14 user.sh
-rw-rw-r--. 1 maxwell maxwell   0 Mar  9 15:18 Maxwell_file
$ echo *
first2.sh Maxwell_file my-script.sh myvar2.sh sorted_data.sh source_data.csv user.sh var2.sh var.sh
$ echo *.sh
first2.sh my-script.sh myvar2.sh sorted_data.sh user.sh var2.sh var.sh
$ echo "*"
*
$ echo "*txt"
*txt
$ 

A quote is ", backslash is \, backtick is `.
A few spaces are    and dollar is $. $X is 5.
$ 
$ export X=5
$ echo "A quote is \", backslash is \\, backtick is \`."
A quote is ", backslash is \, backtick is `.
$ echo "A few spaces are and dollar is \$. \$X is ${X}."
A few spaces are and dollar is $. $X is 5.
$ 

We have seen why the " is special for preserving spacing. Dollar ($) is special because it marks a variable, so $X is replaced by the shell with the contents of the variable X. Backslash (\) is special because it is itself used to mark other characters off; we need the following options for a complete shell:

$ 
$ echo "This is \\ a backslash"
This is \ a backslash
$ echo "This is \" a quote and this is \\ a backslash"
This is " a quote and this is \ a backslash
$ 

7.Loops

Most languages have the concept of loops: If we want to repeat a task twenty times, we don't want to have to type in the code twenty times, with maybe a slight change each time.
As a result, we have for and while loops in the Bourne shell. This is somewhat fewer features than other languages, but nobody claimed that shell programming has the power of C.

$ 
$ vim for.sh
$ sh -x for.sh
+ for i in 1 2 3 4 5
+ echo 'Looping ... number 1'
Looping ... number 1
+ for i in 1 2 3 4 5
+ echo 'Looping ... number 2'
Looping ... number 2
+ for i in 1 2 3 4 5
+ echo 'Looping ... number 3'
Looping ... number 3
+ for i in 1 2 3 4 5
+ echo 'Looping ... number 4'
Looping ... number 4
+ for i in 1 2 3 4 5
+ echo 'Looping ... number 5'
Looping ... number 5
$
$ cat for.sh
#!/bin/sh
for i in 1 2 3 4 5
do
  echo "Looping ... number $i"
done
$ 
$ 
$ vim for2.sh
$ chmod a+rx for2.sh
$ ./for2.sh
Looping ... i is set to hello
Looping ... i is set to 1
Looping ... i is set to first2.sh
Looping ... i is set to for2.sh
Looping ... i is set to for.sh
Looping ... i is set to Maxwell_file
Looping ... i is set to my-script.sh
Looping ... i is set to myvar2.sh
Looping ... i is set to sorted_data.sh
Looping ... i is set to source_data.csv
Looping ... i is set to user.sh
Looping ... i is set to var2.sh
Looping ... i is set to var.sh
Looping ... i is set to 2
Looping ... i is set to goodbye
$ ls -ltr
total 40
-rw-rw-r--. 1 maxwell maxwell 244 Mar  7 19:57 sorted_data.sh
-rw-rw-r--. 1 maxwell maxwell  84 Mar  7 20:00 source_data.csv
-rwxrwxr-x. 1 maxwell maxwell  92 Mar  9 13:15 my-script.sh
-rwxrwxr-x. 1 maxwell maxwell 255 Mar  9 14:32 first2.sh
-rwxrwxr-x. 1 maxwell maxwell  52 Mar  9 14:36 var.sh
-rwxrwxr-x. 1 maxwell maxwell  91 Mar  9 14:42 var2.sh
-rwxrwxr-x. 1 maxwell maxwell  75 Mar  9 14:56 myvar2.sh
-rwxrwxr-x. 1 maxwell maxwell 158 Mar  9 15:14 user.sh
-rw-rw-r--. 1 maxwell maxwell   0 Mar  9 15:18 Maxwell_file
-rw-rw-r--. 1 maxwell maxwell  68 Mar  9 16:16 for.sh
-rwxrwxr-x. 1 maxwell maxwell  83 Mar  9 16:19 for2.sh
$ cat for2.sh
#!/bin/sh
for i in hello 1 * 2 goodbye
do
  echo "Looping ... i is set to $i"
done
$ 

While Loops

while loops can be much more fun!

$ ./while.sh   
Please type something in (bye to quit)
hello
You typed: hello
Please type something in (bye to quit)
bye
You typed: bye
$ cat while.sh
#!/bin/sh
INPUT_STRING=hello
while [ "$INPUT_STRING" != "bye" ]
do
  echo "Please type something in (bye to quit)"
  read INPUT_STRING
  echo "You typed: $INPUT_STRING"
done
$ 

The colon (:) always evaluates to true; whilst using this can be necessary sometimes, it is often preferable to use a real exit condition. Compare quitting the above loop with the one below; see which is the more elegant. Also think of some situations in which each one would be more useful than the other:

$ vim while2.sh       
$ chmod a+rx while2.sh
$ ./while2.sh         
Please type something in (^C to quit)
hello
You typed: hello
Please type something in (^C to quit)
good job!
You typed: good job!
Please type something in (^C to quit)
quit
You typed: quit
Please type something in (^C to quit)
^C
$ cat while2.sh
#!/bin/sh
while :

do
  echo "Please type something in (^C to quit)"
  read INPUT_STRING
  echo "You typed: $INPUT_STRING"

done
$ 

This reads the file "myfile.txt", one line at a time, into the variable "$input_text". The case statement then checks the value of $input_text. If the word that was read from myfile.txt was "hello" then it echoes the word "English". If it was "gday" then it will echo Australian. If the word (or words) read from a line of myfile.txt don't match any of the provided patterns, then the catch-all "*" default will display the message "Unknown Language: $input_text" - where of course "$input_text" is the value of the line that it read in from myfile.txt.

$ 
$ vim while3.sh
$ vim myfile.txt
$ chmod a+rx while3.sh
$ ./while3.sh
Unknown Language: this file is called myfile.txt and we are using it as an example input.
English
Australian
French
Unknown Language: hola
$     
$ cat myfile.txt
this file is called myfile.txt and we are using it as an example input.
hello
gday
bonjour
hola
$ cat while3.sh
#!/bin/sh
while read input_text
do
  case $input_text in
        hello)       echo English    ;;
        howdy)       echo American   ;;
        gday)        echo Australian ;;
        bonjour)     echo French     ;;
        "guten tag") echo German     ;;
        *)           echo Unknown Language: $input_text
                ;;
  esac
done < myfile.txt
$ 

A handy Bash (but not Bourne Shell) tip I learned recently is:

mkdir rc{0,1,2,3,4,5,6,S}.d

instead of the more cumbersome:

for runlevel in 0 1 2 3 4 5 6 S
do
  mkdir rc${runlevel}.d
done

And this can be done recursively, too:

$ 
$ cd /
$ ls -ld {,usr,usr/local}/{bin,sbin,lib}
lrwxrwxrwx.  1 root root     7 Jun 22  2021 /bin -> usr/bin
lrwxrwxrwx.  1 root root     7 Jun 22  2021 /lib -> usr/lib
lrwxrwxrwx.  1 root root     8 Jun 22  2021 /sbin -> usr/sbin
dr-xr-xr-x.  2 root root 49152 Jan 15 11:54 usr/bin
dr-xr-xr-x. 40 root root  4096 Jan 10 09:01 usr/lib
drwxr-xr-x.  2 root root    63 Nov 26 11:20 usr/local/bin
drwxr-xr-x.  2 root root     6 Jun 22  2021 usr/local/lib
drwxr-xr-x.  2 root root     6 Jun 22  2021 usr/local/sbin
dr-xr-xr-x.  2 root root 20480 Jan 15 11:54 usr/sbin
$ 

8. Test

Test is used by virtually every shell script written. It may not seem that way, because test is not often called directly. test is more frequently called as [[ is a symbolic link to test, just to make shell programs more readable. It is also normally a shell builtin (which means that the shell itself will interpret [ as meaning test, even if your Unix environment is set up differently):

$ 
$ type [
[ is a shell builtin
$ which [
/usr/bin/[
$ ls -l /usr/bin/[
-rwxr-xr-x. 1 root root 54872 Jun 24  2022 '/usr/bin/['
$ ls -l /usr/bin/test
-rwxr-xr-x. 1 root root 54816 Jun 24  2022 /usr/bin/test
$ 

This means that '[' is actually a program, just like ls and other programs, so it must be surrounded by spaces:

if [$foo = "bar" ]

will not work; it is interpreted as if test$foo = "bar" ], which is a ']' without a beginning '['. Put spaces around all your operators. 

Test is most often invoked indirectly via the if and while statements. It is also the reason you will come into difficulties if you create a program called test and try to run it, as this shell builtin will be called instead of your program!
The syntax for if...then...else... is:

if [ ... ]
then
  # if-code
else
  # else-code
fi

Note that fi is if backwards! This is used again later with case and esac.

if [ ... ]; then
  # do something
fi

You can also use the elif, like this:

if  [ something ]; then
 echo "Something"
 elif [ something_else ]; then
   echo "Something else"
 else
   echo "None of the above"
fi

This will echo "Something" if the [ something ] test succeeds, otherwise it will test [ something_else ], and echo "Something else" if that succeeds. If all else fails, it will echo "None of the above".

$ X=5        
$ export X   
$ ./test.sh  
X is more than zero
X is more than or equal to zero
X is not the string "hello"
X is of nonzero length
No such file: 5
$ cat test.sh           
#!/bin/sh
if [ "$X" -lt "0" ]
then
   echo "X is less than zero"
fi
if [ "$X" -gt "0" ]; then
   echo "X is more than zero"
fi
[ "$X" -le "0" ] && \
      echo "X is less than or equal to zero"
[ "$X" -ge "0" ] && \
      echo "X is more than or equal to zero"
[ "$X" = "0" ] && \
       echo "X is the string or number \"0\""
[ "$X" = "hello" ] && \
       echo "X is matches the string \"hello\""
[ "$X" != "hello" ] && \
       echo "X is not the string \"hello\""
[ -n "$X" ] && \
       echo "X is of nonzero length"
[ -f "$X" ] && \
       echo "X is the path of a real file" || \
       echo "No such file: $X"
[ -x "$X" ] && \
       echo "X is the path of an executable file"
[ "$X" -nt "/etc/passwd" ] && \
      echo "X is a file Which is newer than /etc/passwd"
$ 

《计算理论导论》(Introduction to the Theory of Computation)是一本经典的计算机科学教材,适用于理论计算机科学领域的学生和研究人员。这本书由Michael Sipser所著,第一版于1997年出版,目前已经出版了第三版。 《计算理论导论》的目标是介绍计算理论的基本概念和技巧。它涵盖了计算能力、形式语言、自动机理论、图灵机、可计算性、复杂性理论等主题。每个主题都以清晰的解释、例子和练习来展示,使读者能够理解和应用这些概念。 这本书的特点之一是强调形式化和精确性。它使用数学语言和符号来定义概念和理论,并提供了形式的证明过程。这种精确性有助于读者深入理解计算理论的基本原理和证明方法。 书中还包含了一些重要的应用,例如正则表达式、编程语言的语法分析、有限状态机的设计等。这些应用展示了计算理论在实际计算机科学领域的应用和重要性。 《计算理论导论》可以作为计算机科学相关专业的教材使用,也适用于自学者。读者需要有一定的数学基础,如离散数学和数理逻辑,以便更好地理解和运用书中的概念和技巧。 总之,《计算理论导论》是一本经典的计算机科学教材,它通过清晰的解释、精确的定义和形式化的证明,帮助读者理解计算理论的基本概念和技巧,并展示了其在实际应用中的重要性。无论是理论计算机科学领域的学生还是研究人员,都可以从中受益。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值