Shell Scripting part2

 This code will keep asking for input until you hit RETURN (X is zero length). Thanks to Justin Heath for pointing out that the script didn't work - I'd missed out the quotes around $X in the while [ -n "$X" ]. Without those quotes, there is nothing to test when $X is empty.

$ ./test2.sh
Enter some text (RETURN to quit)
fred
You said: fred
Enter some text (RETURN to quit)
wilma
You said: wilma
Enter some text (RETURN to quit)
quit
You said: quit
Enter some text (RETURN to quit)

You said: 
$ 
$ cat test2.sh
#!/bin/sh
X=0
while [ -n "$X" ]
do
  echo "Enter some text (RETURN to quit)"
  read X
  echo "You said: $X"
done
$ 

9. Case

The case statement saves going through a whole set of if .. then .. else statements. Its syntax is really quite simple:

$ 
$ vim talk.sh
$ chmod 775 talk.sh
$ 
$ ./talk.sh
Please talk to me ...
hello
Hello yourself!
What do you think of politics?
Sorry, I don't understand
bye  
See you again!

That's all folks!
$ 
$ cat talk.sh
#!/bin/sh

echo "Please talk to me ..."
while :
do
  read INPUT_STRING
  case $INPUT_STRING in
       hello)
               echo "Hello yourself!"
               ;;
       bye)
               echo "See you again!"
               break
               ;;
       *)
               echo "Sorry, I don't understand"
               ;;
  esac
done
echo
echo "That's all folks!"
$ 

The syntax is quite simple:
The case line itself is always of the same format, and it means that we are testing the value of the variable INPUT_STRING.


The options we understand are then listed and followed by a right bracket, as hello) and bye).
This means that if INPUT_STRING matches hello then that section of code is executed, up to the double semicolon.
If INPUT_STRING matches bye then the goodbye message is printed and the loop exits. Note that if we wanted to exit the script completely then we would use the command exit instead of break.
The third option here, the *), is the default catch-all condition; it is not required, but is often useful for debugging purposes even if we think we know what values the test variable will have.

The whole case statement is ended with esac (case backwards!) then we end the while loop with a done.

10. Variables - Part II

There are a set of variables which are set for you already, and most of these cannot have values assigned to them.
These can contain useful information, which can be used by the script to know about the environment in which it is running.

The first set of variables we will look at are $0 .. $9 and $#.
The variable $0 is the basename of the program as it was called.
$1 .. $9 are the first 9 additional parameters the script was called with.
The variable $@ is all parameters $1 .. whatever. The variable $*, is similar, but does not preserve any whitespace, and quoting, so "File with spaces" becomes "File" "with" "spaces". This is similar to the echo stuff .As a general rule, use $@ and avoid $*.
$# is the number of parameters the script was called with.

var3.sh

$ 
$ cat var3.sh
#!/bin/sh
echo "I was called with $# parameters"
echo "My name is $0"
echo "My first parameter is $1"
echo "My second parameter is $2"
echo "All parameter are $@"
$ 
$ 
$ 

Let's look at running this code and see the output:

$ 
$ vim var3.sh
$ chmod 775 var3.sh
$ 
$ pwd
/home/maxwell/projects/shell_20230320
$ /home/maxwell/projects/shell_20230320/var3.sh
I was called with 0 parameters
My name is /home/maxwell/projects/shell_20230320/var3.sh
My first parameter is 
My second parameter is 
All parameter are 
$ 
$ ./var3.sh hello world earth
I was called with 3 parameters
My name is ./var3.sh
My first parameter is hello
My second parameter is world
All parameter are hello world earth
$

Note that the value of $0 changes depending on how the script was called. The external utility basename can help tidy this up:

echo "My name is `basename $0`"

$# and $1 .. $9 are set automatically by the shell.

We can take more than 9 parameters by using the shift command; look at the script below:

$ 
$ vim var4.sh
$ 
$ chmod 775 var4.sh
$ 
$ cat var4.sh
#!/bin/sh
while [ "$#" -gt "0" ]
do
  echo "\$1 is $1"
  shift
done
$ 




This script keeps on using shift until $# is down to zero, at which point the list is empty.

Another special variable is $?. This contains the exit value of the last run command. So the code:

#!/bin/sh
/usr/local/bin/my-command
if [ "$?" -ne "0" ]; then
  echo "Sorry, we had a problem there!"
fi

will attempt to run /usr/local/bin/my-command which should exit with a value of zero if all went well, or a nonzero value on failure. We can then handle this by checking the value of $? after calling the command. This helps make scripts robust and more intelligent.

在shell中,"$?"是一个特殊的shell变量,它存储了上一个执行的命令的退出状态。

当一个命令被执行时,它会返回一个退出状态码,用于指示该命令是否成功执行。"$?"的值被设置为该退出状态码。

"$?"的值为0表示上一个命令成功执行,而非零值表示有错误发生。

您可以在shell脚本中使用"$?"来检查前一个命令的退出状态,并根据该状态采取适当的操作。例如,您可以使用“if”语句检查"$?"是否等于0,如果是则执行一些代码,否则执行不同的代码。

The other two main variables set for you by the environment are $$ and $!. These are both process numbers.
The $$ variable is the PID (Process IDentifier) of the currently running shell. This can be useful for creating temporary files, such as /tmp/my-script.$$ which is useful if many instances of the script could be run at the same time, and they all need their own temporary files.

 

The $! variable is the PID of the last run background process. This is useful to keep track of the process as it gets on with its job.

Another interesting variable is IFS. This is the Internal Field Separator. The default value is SPACE TAB NEWLINE, but if you are changing it, it's easier to take a copy, as shown:

在shell中,"$$"和"$!"都是特殊的变量,分别用于获取当前进程的进程ID(PID)和上一个异步进程的PID。

  • "$$" 变量返回当前进程的PID,它是一个唯一的数字标识符,用于标识该进程在操作系统中的位置。您可以使用它来识别当前正在运行的进程,或将其作为锁文件名称的一部分,以确保在同一时间只有一个实例运行。

  • "$!" 变量返回上一个异步进程的PID,当您在后台运行一个命令时,该命令将在后台运行,并且"$!"变量将返回该命令的PID。您可以使用它来等待该命令的完成,或使用它来检查进程的状态。

例如,假设您在后台运行了一个长时间运行的脚本:

./long_script.sh &

在这种情况下,"$!"将返回该脚本的PID。您可以使用它来等待该脚本的完成:

wait $!

或者您可以使用它来检查该脚本的状态:

kill -0 $!
if [ $? -eq 0 ]; then
    echo "The script is still running."
else
    echo "The script has finished."
fi
$ 
$ vim var5.sh
$ 
$ chmod 775 var5.sh
$ 
$ ./var5.sh
Please input some data separated by colons ...
hello:how are you:today
x is hello y is how are you z is today
$ 
$ 
$ ./var5.sh
Please input some data separated by colons ...
hello:how are you:today:my:friend
x is hello y is how are you z is today:my:friend
$ 
$ 
$ cat var5.sh
#!/bin/sh
old_IFS="$IFS"
IFS=:
echo "Please input some data separated by colons ..."
read x y z
IFS=$old_IFS
echo "x is $x y is $y z is $z"
$ 
$ 

11. Variables - Part III

curly brackets around a variable avoid confusion:

$ 
$ foo=sun
$ echo $fooshine  # $ fooshine is undefined

$ echo ${foo}shine # displays the word "sunshine"
sunshine
$ 
$ 

Using Default Values

Consider the following code snippet which prompts the user for input, but accepts defaults:

$ 
$ vim name.sh
$ 
$ chmod 775 name.sh
$ 
$ ./name.sh
What is your name [ maxwell ] 
Your name is : maxwell
$ 
$ 
$ cat name.sh
#!/bin/sh
echo -en "What is your name [ `whoami` ] "
read myname
if [ -z "$myname" ]; then
  myname=`whoami`
fi
echo "Your name is : $myname"
$ 

Passing the "-en" to echo tells it not to add a linebreak (for bash and csh). For Dash, Bourne and other compliant shells, you use a "\c" at the end of the line, instead. Ksh understands both form

This script runs like this if you accept the default by pressing "RETURN":

$ 
$ 
$ ./name.sh
What is your name [ maxwell ] 
Your name is : maxwell
$ 
$ ./name.sh
What is your name [ maxwell ] foo
Your name is : foo
$ 
$

12. External Programs

External programs are often used within shell scripts; there are a few builtin commands (echowhich, and test are commonly builtin), but many useful commands are actually Unix utilities, such as trgrepexpr and cut.

The backtick (`)is also often associated with external commands. Because of this, we will discuss the backtick first.
The backtick is used to indicate that the enclosed text is to be executed as a command. This is quite simple to understand. First, use an interactive shell to read your full name from /etc/passwd:

$ 
$ grep "^${USER}:" /etc/passwd | cut -d: -f5
maxwell
$ 
$ 

Now we will grab this output into a variable which we can manipulate more easily:

$ 
$ MYNAME=`grep "^${USER}:" /etc/passwd | cut -d: -f5`
$ echo $MYNAME
maxwell
$ 

So we see that the backtick simply catches the standard output from any command or set of commands we choose to run. It can also improve performance if you want to run a slow command or set of commands and parse various bits of its output:

#!/bin/sh
find / -name "*.html" -print | grep "/index.html$"
find / -name "*.html" -print | grep "/contents.html$"

this code could take a long time to run, and we are doing it twice!

A better solution is:

#!/bin/sh
HTML_FILES=`find / -name "*.html" -print`
echo "$HTML_FILES" | grep "/index.html$"
echo "$HTML_FILES" | grep "/contents.html$"

Note: the quotes around $HTML_FILES are essential to preserve the newlines between each file listed. Otherwise, grep will see one huge long line of text, and not one line per file.

This way, we are only running the slow find once, roughly halving the execution time of the script.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值