常用shell命令
将终端的背景色设置成白色、文本设置成黑色
setterm -inversescreen on
Linux中常见的几种不同 shell
常见Linux目录名称
/ 虚拟目录的根目录。通常不会在这里存储文件
/bin 二进制目录,存放许多用户级的GNU工具 4 /boot 启动目录,存放启动文件
/dev 设备目录,Linux在这里创建设备节点
/etc 系统配置文件目录 5 /home 主目录,Linux在这里创建用户目录
/lib 库目录,存放系统和应用程序的库文件
/media 媒体目录,可移动媒体设备的常用挂载点 6 /mnt 挂载目录,另一个可移动媒体设备的常用挂载点
/opt 可选目录,常用于存放第三方软件包和数据文件
/proc 进程目录,存放现有硬件及当前进程的相关信息
/root root用户的主目录
/sbin 系统二进制目录,存放许多GNU管理员级工具
/run 运行目录,存放系统运作时的运行时数据
/srv 服务目录,存放本地服务的相关文件
/sys 系统目录,存放系统硬件信息的相关文件
/tmp 临时目录,可以在该目录中创建和删除临时工作文件
/usr 用户二进制目录,大量用户级的GNU工具和数据文件都存储在这里
/var 可变目录,用以存放经常变化的文件,比如日志文件
ls -F
-F参数在目录名后加了正斜线(/),以方便用户在输出中分辨它们。类似地,它会在可执行 文件(比如上面的my_script文件)的后面加个星号,以便用户找出可在系统上运行的文件。
ls -R
-R参数是ls命令可用的另一个参数,叫作递归选项。它列出了当前目录下包含的子目录中 的文件。如果目录很多,这个输出就会很长。以下是-R参数输出的简单例子:
ls -l
ls命令并未输出太多每个文件的相关信息。要显示附加信息,另一个
常用的参数是-l。-l参数会产生长列表格式的输出,包含了目录中每个文件的更多相关信息。
过滤输出列表
当用户指定特定文件的名称作为过滤器时,ls命令只会显示该文件的信息。有时你可能不知 道要找的那个文件的确切名称。ls命令能够识别标准通配符,并在过滤器中用它们进行模式匹配:
问号(?)代表一个字符;
星号(*)代表零个或多个字符
问号可用于过滤器字符串中替代任意位置的单个字符
可以利用type命令来了解某个命令是否是内建的
查看全局环境变量
全局环境变量对于shell会话和所有生成的子shell都是可见的。局部变量则只对创建它们的 shell可见。这让全局环境变量对那些所创建的子shell需要获取父shell信息的程序来说非常有用。
Linux系统在你开始bash会话时就设置了一些全局环境变量(如想了解此时设置了哪些变量)。系统环境变量基本上都是使用全大写字母,以区别于普通用户的环境变量。
要查看全局变量,可以使用env或printenv命令 。
要显示个别环境变量的值,可以使用printenv命令
env、printenv和set之间的差异
命令env、printenv和set之间的差异很细微。set命令会显示出全局变量、局部变量以 及用户定义变量。它还会按照字母顺序对结果进行排序。env和printenv命令同set命 令的区别在于前两个命令不会对变量排序,也不会输出局部变量和用户定义变量。在这 种情况下,env和printenv的输出是重复的。不过env命令有一个printenv没有的功能, 这使得它要更有用一些。
设置全局环境变量
先创建一个局部环境变量,然后再把它导出到全局环境中。
这个过程通过export命令来完成,变量名前面不需要加$。
删除环境变量
在unset命令中引用环境变量时,记住不要使用$。
删除用户
下面是用userdel命令删除已有用户账户的一个例子。
加了-r参数后,用户先前的那个/home/test目录已经不存在了。
添加新用户
-m 创建用户的HOME目录
替换命令
可以对替换命令作一些修改来替
换多处文本。
q :s/old/new/g:一行命令替换所有old。
q :n,ms/old/new/g:替换行号n和m之间所有old。
q :%s/old/new/g:替换整个文件中的所有old。
q :%s/old/new/gc:替换整个文件中的所有old,但在每次出现时提示。
wc命令
通过将文本文件重定向到wc命令,你立刻就可以得到文件中的行、词和字节的计数。这个例 子说明test6文件有2行、11个单词以及60字节。
if-then-elif嵌套组合
文件比较
-d测试会检查指定的目录是否存在于系统中。如果你打算将文件写入目录或是准备切换到某 个目录中,先进行测试总是件好事情。
检查是否可读
检查空文件
应该用-s比较来检查文件是否为空,尤其是在不想删除非空文件的时候。要留心的是,当 -s比较成功时,说明文件中有数据。
检查是否可写
item_name=$HOME/sentinel if [ -w $item_name ] then echo "Writing current time to $item_name" date +%H%M >> $item_name else echo "Unable to write to $item_name" fi
检查文件是否可以执行
检查所属关系
-O比较可以测试出你是否是文件的属主。
#!/bin/bash
if [ -O /etc/passwd ]
then
echo "You are the owner of the /etc/passwd file"
else
echo "Sorry, you are not the owner of the /etc/passwd file"
fi
检查默认属组关系
-G比较会检查文件的默认组,如果它匹配了用户的默认组,则测试成功。
检查文件日期
-nt比较会判定一个文件是否比另一个文件新。如果文件较新,那意味着它的文件创建日 期更近。-ot比较会判定一个文件是否比另一个文件旧。如果文件较旧,意味着它的创建日期 更早。
复合条件测试
if-then语句允许你使用布尔逻辑来组合测试。有两种布尔运算符可用:
q [ condition1 ] && [ condition2 ]
q [ condition1 ] || [ condition2 ]
使用双括号
双括号命令允许你在比较过程中使用高级数学表达式。test命令只能在比较中使用简单的 算术操作。双括号命令提供了更多的数学符号 。
Code
双方括号
双方括号命令提供了针对字符串比较的高级特性。
在上面的脚本中,我们使用了双等号(==)。双等号将右边的字符串(r*)视为一个模式, 并应用模式匹配规则。双方括号命令$USER环境变量进行匹配,看它是否以字母r开头。如果是 的话,比较通过,shell会执行then部分的命令。
case命令
较长的if语句
#!/bin/bash # looking for a possible value if [ $USER = "rich" ] then echo "Welcome $USER" echo "Please enjoy your visit" elif [ $USER = "barbara" ] then echo "Welcome $USER" echo "Please enjoy your visit" elif [ $USER = "testing" ] then echo "Special testing account" elif [ $USER = "jessica" ] then echo "Do not forget to logout when you're done" else echo "Sorry, you are not allowed here" fi
case版本
for命令
for命令最基本的用法就是遍历for命令自身所定义的一系列值。
每次for命令遍历值列表,它都会将列表中的下个值赋给$test变量。$test变量可以像for 命令语句中的其他脚本变量一样使用。在最后一次迭代后,$test变量的值会在shell脚本的剩余 部分一直保持有效。它会一直保持最后一次迭代的值(除非你修改了它)。
读取列表中的复杂值
有两种办法可解决这个问题:
q 使用转义字符(反斜线)来将单引号转义;
q 使用双引号来定义用到单引号的值。
这两种解决方法并没有什么出奇之处,但都能解决这个问题。
for命令用空格来划分列表中的每个值。如果在单独的数据值中有 空格,就必须用双引号将这些值圈起来。
更改字段分隔符
#
#!/bin/bash # reading values from a file file="states" IFS=$'\n' for state in $(cat $file) do echo "Visit beautiful $state" done $ ./test5b Visit beautiful Alabama Visit beautiful Alaska Visit beautiful Arizona Visit beautiful Arkansas Visit beautiful Colorado Visit beautiful Connecticut Visit beautiful Delaware Visit beautiful Florida Visit beautiful Georgia Visit beautiful New York Visit beautiful New Hampshire Visit beautiful North Carolina
从变量读取列表
#!/bin/bash # using a variable to hold the list list="Alabama Alaska Arizona Arkansas Colorado" list=$list" Connecticut" for state in $list do echo "Have you ever visited $state?" done $ ./test4 Have you ever visited Alabama? Have you ever visited Alaska? Have you ever visited Arizona? Have you ever visited Arkansas? Have you ever visited Colorado? Have you ever visited Connecticut?
从命令读取值
用通配符读取目录
也可以在for命令中列出多个目录通配符,将目录查找和列表合并进同一个for语句。
#!/bin/bash # iterating through multiple directories for file in /home/rich/.b* /home/rich/badtest do if [ -d "$file" ] then echo "$file is a directory" elif [ -f "$file" ] then echo "$file is a file" else echo "$file doesn't exist" fi done
以下例子是在bash shell程序中使用C语言风格的for命令
使用多个变量
while命令
#!/bin/bash # while command test var1=10 while [ $var1 -gt 0 ] do echo $var1 var1=$[ $var1 - 1 ] done $ ./test10 10 9 8 7 6 5 4 3 2 1
使用多个测试命令
#!/bin/bash # testing a multicommand while loop var1=10 while echo $var1 [ $var1 -ge 0 ] do echo "This is inside the loop" var1=$[ $var1 - 1 ] done $ ./test11 10 This is inside the loop 9 This is inside the loop 8 This is inside the loop 7 This is inside the loop 6 This is inside the loop 5 This is inside the loop 4 This is inside the loop 3 This is inside the loop 2 This is inside the loop 1 This is inside the loop 0 This is inside the loop -1
while循环会在var1变量等于0时执行echo语句,然后将var1变量的值减一。接下来再次执 行测试命令,用于下一次迭代。echo测试命令被执行并显示了var变量的值(现在小于0了)。直 到shell执行test测试命令,whle循环才会停止。
这说明在含有多个命令的while语句中,在每次迭代中所有的测试命令都会被执行,包括测 试命令失败的最后一次迭代。要留心这种用法。另一处要留意的是该如何指定多个测试命令。注 意,每个测试命令都出现在单独的一行上。
until命令
1.
2.
for循环中嵌套for循环
while循环嵌套for循环
$ cat test15 #!/bin/bash # placing a for loop inside a while loop var1=5 while [ $var1 -ge 0 ] do echo "Outer loop: $var1" for (( var2 = 1; $var2 < 3; var2++ )) do var3=$[ $var1 * $var2 ] echo " Inner loop: $var1 * $var2 = $var3" done var1=$[ $var1 - 1 ] done $ ./test15 Outer loop: 5 Inner loop: 5 * 1 = 5 Inner loop: 5 * 2 = 10 Outer loop: 4 Inner loop: 4 * 1 = 4 Inner loop: 4 * 2 = 8 Outer loop: 3 Inner loop: 3 * 1 = 3 Inner loop: 3 * 2 = 6 Outer loop: 2 Inner loop: 2 * 1 = 2 Inner loop: 2 * 2 = 4 Outer loop: 1 Inner loop: 1 * 1 = 1 Inner loop: 1 * 2 = 2 Outer loop: 0 Inner loop: 0 * 1 = 0 Inner loop: 0 * 2 = 0
until与while嵌套
$ cat test16 #!/bin/bash # using until and while loops var1=3 until [ $var1 -eq 0 ] do echo "Outer loop: $var1" var2=1 while [ $var2 -lt 5 ] do var3=$(echo "scale=4; $var1 / $var2" | bc) echo " Inner loop: $var1 / $var2 = $var3" var2=$[ $var2 + 1 ] done var1=$[ $var1 - 1 ] done $ ./test16 Outer loop: 3 Inner loop: 3 / 1 = 3.0000 Inner loop: 3 / 2 = 1.5000 Inner loop: 3 / 3 = 1.0000 Inner loop: 3 / 4 = .7500 Outer loop: 2 Inner loop: 2 / 1 = 2.0000 Inner loop: 2 / 2 = 1.0000 Inner loop: 2 / 3 = .6666 Inner loop: 2 / 4 = .5000 Outer loop: 1 Inner loop: 1 / 1 = 1.0000 Inner loop: 1 / 2 = .5000 Inner loop: 1 / 3 = .3333 Inner loop: 1 / 4 = .2500 $
循环处理文件数据
通过修改IFS环境变量,就能强制for命令将文件中的每行都当成单独的一个条目来处理, 即便数据中有空格也是如此。一旦从文件中提取出了单独的行,可能需要再次利用循环来提取行 中的数据。
典型的例子是处理/etc/passwd文件中的数据。这要求你逐行遍历/etc/passwd文件,并将IFS 变量的值改成冒号,这样就能分隔开每行中的各个数据段了。
结果
Values in rich:x:501:501:Rich Blum:/home/rich:/bin/bash - rich x 501 501 Rich Blum /home/rich /bin/bash Values in katie:x:502:502:Katie Blum:/home/katie:/bin/bash - katie x 506 509 Katie Blum /home/katie /bin/bash
跳出for循环
$ cat test17 #!/bin/bash # breaking out of a for loop for var1 in 1 2 3 4 5 6 7 8 9 10 do if [ $var1 -eq 5 ] then break fi echo "Iteration number: $var1" done echo "The for loop is completed" $ ./test17 Iteration number: 1 Iteration number: 2 Iteration number: 3 Iteration number: 4 The for loop is completed $
跳出while循环
$ cat test18 #!/bin/bash var1=1 while [ $var1 -lt 10 ] do if [ $var1 -eq 5 ] then break fi echo "Iteration: $var1" var1=$[ $var1 + 1 ] done echo "The while loop is completed" $ ./test18 Iteration: 1 Iteration: 2 Iteration: 3 Iteration: 4 The while loop is completed $
处理多个循环时,break命令会自动终止你所在的最内层的循环
$ cat test19 #!/bin/bash # breaking out of an inner loop for (( a = 1; a < 4; a++ )) do echo "Outer loop: $a" for (( b = 1; b < 100; b++ )) do if [ $b -eq 5 ] then break fi echo " Inner loop:$b" done done $ ./test19 Outer loop: 1 Inner loop: 1 Inner loop: 2 Inner loop: 3 Inner loop: 4 Outer loop: 2 Inner loop: 1 Inner loop: 2 Inner loop: 3 Inner loop: 4 Outer loop: 3 Inner loop: 1 Inner loop: 2 Inner loop: 3 Inner loop: 4 $
跳出多层循环
$ cat test20 #!/bin/bash # breaking out of an outer loop for (( a = 1; a < 4; a++ )) do echo "Outer loop: $a" for (( b = 1; b < 100; b++ )) do if [ $b -gt 4 ] then break 2 fi echo " Inner loop: $b" done done $ ./test20 Outer loop: 1 Inner loop: 1 Inner loop: 2 Inner loop: 3 Inner loop: 4 $
continue命令
$ cat test21 #!/bin/bash # using the continue command for (( var1 = 1; var1 < 15; var1++ )) do if [ $var1 -gt 5 ] && [ $var1 -lt 10 ] then continue fi echo "Iteration number: $var1" done $ ./test21 Iteration number: 1 Iteration number: 2 Iteration number: 3 Iteration number: 4 Iteration number: 5 Iteration number: 10 Iteration number: 11 Iteration number: 12 Iteration number: 13 Iteration number: 14 $
值为3的那次迭代并没有处理任何内部循环语句,因为尽管continue命令停止了处理,但外部循环依然会继续。
$ cat test22 #!/bin/bash # continuing an outer loop for (( a = 1; a <= 5; a++ )) do echo "Iteration $a:" for (( b = 1; b < 3; b++ )) do if [ $a -gt 2 ] && [ $a -lt 4 ] then continue 2 fi var3=$[ $a * $b ] echo " The result of $a * $b is $var3" done echo "***********" done $ ./test22 Iteration 1: The result of 1 * 1 is 1 The result of 1 * 2 is 2 *********** Iteration 2: The result of 2 * 1 is 2 The result of 2 * 2 is 4 *********** Iteration 3: Iteration 4: The result of 4 * 1 is 4 The result of 4 * 2 is 8 *********** Iteration 5: The result of 5 * 1 is 5 The result of 5 * 2 is 10 ***********
将循环输出结果重定向
1.
for file in /home/rich/* do if [ -d "$file" ] then echo "$file is a directory" elif echo "$file is a file" fi done > output.txt
2.
$ cat test23 #!/bin/bash # redirecting the for output to a file for (( a = 1; a < 10; a++ )) do echo "The number is $a" done > test23.txt echo "The command is finished." $ ./test23 The command is finished. $ cat test23.txt The number is 1 The number is 2 The number is 3 The number is 4 The number is 5 The number is 6 The number is 7 The number is 8 The number is 9 $
3.
$ cat test24 #!/bin/bash # piping a loop to another command for state in "North Dakota" Connecticut Illinois Alabama Tennessee do echo "$state is the next place to go" done | sort echo "This completes our travels" $ ./test24 Alabama is the next place to go Connecticut is the next place to go Illinois is the next place to go North Dakota is the next place to go Tennessee is the next place to go This completes our travels
创建多个用户账户
$ cat users.csv rich,Richard Blum christine,Christine Bresnahan barbara,Barbara Blum tim,Timothy Bresnahan $ $ cat test26 #!/bin/bash # process new user accounts input="users.csv" while IFS=',' read -r userid name do echo "adding $userid" useradd -c "$name" -m $userid done < "$input" $
必须作为root用户才能运行这个脚本,因为useradd命令需要root权限。
# ./test26
adding rich
adding christine
adding barbara
adding tim
#
来看一眼/etc/passwd文件,你会发现账户已经创建好了。
# tail /etc/passwd
rich:x:1001:1001:Richard Blum:/home/rich:/bin/bash christine:x:1002:1002:Christine Bresnahan:/home/christine:/bin/bash barbara:x:1003:1003:Barbara Blum:/home/barbara:/bin/bash tim:x:1004:1004:Timothy Bresnahan:/home/tim:/bin/bash
#
求一个数的阶乘
求两个数的乘积
Basename 返回不包含路径的脚本名
$ cat test5.sh #!/bin/bash # Testing the $0 parameter echo The zero parameter is set to: $0 $ $ ./test5.sh The zero parameter is set to: ./test5.sh $ $ bash /home/Christine/test5.sh The zero parameter is set to: /home/Christine/test5.sh
bogon:Desktop macname$ basename /opt/bp/ssss.txt
ssss.txt
bogon:Desktop macname$
在两种情况下都会先获得脚本的基本名称,然后根据该值执行相应的功能。
$ cat test6.sh #!/bin/bash name=$(basename $0) if [ $name = "addem" ] then total=$[ $1 + $2 ] elif [ $name = "multem" ] then total=$[ $1 * $2 ] fi echo echo The calculated value is $total $ $ $ cp test6.sh addem $ chmod u+x addem $ $ ln -s test6.sh multem $ $ ./addem 2 5 The calculated value is 7 $ $ ./multem 2 5 The calculated value is 10 $
接收参数并且检查其中是否存在数据
特殊变量$#含有脚本运行时携带的命令行参数的个数。
参数的长度
对参数的检查
1.
$ cat test9.sh #!/bin/bash if [ $# -ne 2 ] then echo echo Usage: test9.sh a b echo else total=$[ $1 + $2 ] echo echo The total is $total echo fi $ $ $ bash test9.sh Usage: test9.sh a b $ bash test9.sh 10 Usage: test9.sh a b $ bash test9.sh 10 15 The total is 25 $
这个测试将$#变量的值赋给了变量params,然后也按特殊命令行参数变量的格式使用了该变量。两种方法都没问题。
重要的是要注意,当命令行上没有任何参数时,$#的值为0, params变量的值也一样,但${!#}变量会返回命令行用到的脚本名。
2. $ cat test10.sh #!/bin/bash params=$# echo echo The last parameter is $params echo The last parameter is ${!#} echo $ $ $ bash test10.sh 1 2 3 4 5 The last parameter is 5 The last parameter is 5 $ $ bash test10.sh The last parameter is 0 The last parameter is test10.sh $
$*与$@
$*变量会将所有参数合并为一个参数,而$@变量会单独处理每个参数。
test.sh #!/bin/bash echo count=1 for param in "$*" do echo "__________\$* Parameter #$count = $param" count=$[ $count + 1 ] done echo count=1 for param in "$@" do echo "***********\$@ Parameter #$count = $param" count=$[ $count + 1 ] done 输出 bogon:Desktop macname$ ./test.sh xiaoming xiaohong xiaodong xiaoli __________$* Parameter #1 = xiaoming xiaohong xiaodong xiaoli ***********$@ Parameter #1 = xiaoming ***********$@ Parameter #2 = xiaohong ***********$@ Parameter #3 = xiaodong ***********$@ Parameter #4 = xiaoli
移动变量
这个脚本通过测试第一个参数值的长度执行了一个while循环。
当第一个参数的长度为零 时,循环结束。
测试完第一个参数后,shift命令会将所有参数的位置移动一个位置。
使用shift命令的时候要小心。如果某个参数被移出,它的值就被丢弃了,无法再恢复。
$ cat test13.sh #!/bin/bash # demonstrating the shift command echo count=1 while [ -n "$1" ] do echo "Parameter #$count = $1" count=$[ $count + 1 ] shift done $ $ ./test13.sh rich barbara katie jessica Parameter #1 = rich Parameter #2 = barbara Parameter #3 = katie Parameter #4 = jessica $
增大跨度
$ cat test14.sh #!/bin/bash echo echo "The original parameters: $*" shift 2 echo "Here's the new first parameter: $1" $ $ ./test14.sh 1 2 3 4 5 The original parameters: 1 2 3 4 5 Here's the new first parameter: 3 $
参数传递查找选项
$ cat test15.sh #!/bin/bash # extracting command line options as parameters # echo while [ -n "$1" ] do case "$1" in -a) echo "Found the -a option" ;; -b) echo "Found the -b option" ;; -c) echo "Found the -c option" ;; *) echo "$1 is not an option" ;; esac shift done $ $ ./test15.sh -a -b -c -d Found the -a option Found the -b option Found the -c option -d is not an option $ $ ./test15.sh -d -c -a -d is not an option Found the -c option Found the -a option $
分离参数和选项
$ cat test16.sh #!/bin/bash # extracting options and parameters echo while [ -n "$1" ] do case "$1" in -a) echo "Found the -a option" ;; -b) echo "Found the -b option";; -c) echo "Found the -c option" ;; --) shift break ;; *) echo "$1 is not an option";; esac shift done count=1 for param in $@ do echo "Parameter #$count: $param" count=$[ $count + 1 ] done $ $ ./test16.sh -c -a -b test1 test2 test3 Found the -c option Found the -a option Found the -b option test1 is not an option test2 is not an option test3 is not an option $ $ ./test16.sh -c -a -b -- test1 test2 test3 Found the -c option Found the -a option Found the -b option Parameter #1: test1 Parameter #2: test2 Parameter #3: test3 $
处理带值的选项
$cat test.sh #!/bin/bash # extracting command line options and values echo while [ -n "$1" ] do case "$1" in -a) echo "Found the -a option";; -b) param="$2" echo "Found the -b option, with parameter value $param" shift ;; -c) echo "Found the -c option";; --) shift break ;; *) echo "$1 is not an option";; esac shift done count=1 for param in "$@" do echo "Parameter #$count: $param" count=$[ $count + 1 ] done $ $ ./test.sh -a -b test1 -d -s dedede -- hjhj Found the -a option Found the -b option, with parameter value test1 -d is not an option -s is not an option dedede is not an option Parameter #1: hjhj $ $
使用getopt命令
$cat test.sh #!/bin/bash # Extract command line options & values with getopt echo while [ -n "$1" ] do case "$1" in -a) echo "Found the -a option" ;; -b) param="$2" echo "Found the -b option, with parameter value $param" shift ;; -c) echo "Found the -c option" ;; --) shift break ;; *) echo "$1 is not an option";; esac shift done count=1 for param in "$@" do echo "Parameter #$count: $param" count=$[ $count + 1 ] done $ $ ./test.sh -a -b test1 -cd test2 test3 test4 -- swsw Found the -a option Found the -b option, with parameter value test1 -cd is not an option test2 is not an option test3 is not an option test4 is not an option Parameter #1: swsw $
高级的getopts
1. $cat test.sh #!/bin/bash # simple demonstration of the getopts command # echo while getopts :ab:c opt do case "$opt" in a) echo "Found the -a option" ;; b) echo "Found the -b option, with value $OPTARG";; c) echo "Found the -c option" ;; *) echo "Unknown option: $opt";; esac done $ $ ./test.sh -ab test1 -c Found the -a option Found the -b option, with value test1 Found the -c option $ $ ./test.sh -b "test1 test2" -a Found the -b option, with value test1 test2 Found the -a option $ $ ./test.sh -abtest1 Found the -a option Found the -b option, with value test1 $ $ ./test.sh -d Unknown option: ? $ $ ./test.sh -acde Found the -a option Found the -c option Unknown option: ? Unknown option: ? $ 2. $ cat test20.sh #!/bin/bash # Processing options & parameters with getopts # echo while getopts :ab:cd opt do case "$opt" in a) echo "Found the -a option" ;; b) echo "Found the -b option, with value $OPTARG" ;; c) echo "Found the -c option" ;; d) echo "Found the -d option" ;; *) echo "Unknown option: $opt" ;; esac done shift $[ $OPTIND - 1 ] echo count=1 for param in "$@" do echo "Parameter $count: $param" count=$[ $count + 1 ] done $ $ $ ./test20.sh -a -b test1 -d test2 test3 test4 Found the -a option Found the -b option, with value test1 Found the -d option Parameter 1: test2 Parameter 2: test3 Parameter 3: test4 $
获得用户输入
$ cat test21.sh #!/bin/bash # testing the read command echo -n "Enter your name: " read name echo "Hello $name, welcome to my program. " $ $ ./test21.sh Enter your name: Rich Blum Hello Rich Blum, welcome to my program. $ $ $ cat test22.sh #!/bin/bash # testing the read -p option read -p "Please enter your age: " age days=$[ $age * 365 ] echo "That makes you over $days days old! " $ $ ./test22.sh Please enter your age: 10 That makes you over 3650 days old! $ $ $ cat test23.sh #!/bin/bash # entering multiple variables read -p "Enter your name: " first last echo "Checking data for $last, $first..." $ $ ./test23.sh Enter your name: Rich Blum Checking data for Blum, Rich... $ $ $ cat test24.sh #!/bin/bash # Testing the REPLY Environment variable read -p "Enter your name: " echo echo Hello $REPLY, welcome to my program. $ $ ./test24.sh Enter your name: Christine Hello Christine, welcome to my program. $
也可以在read命令行中不指定变量。如果是这样,read命令会将它收到的任何数据都放进 特殊环境变量REPLY中。
REPLY环境变量会保存输入的所有数据,可以在shell脚本中像其他变量一样使用。
超时
如果计时器过期,read命令会以非零退出状态码退出,可以使用如if-then语句或while 循环这种标准的结构化语句来理清所发生的具体情况。
在本例中,计时器过期时,if语句不成立, shell会执行else部分的命令。
$ cat test25.sh #!/bin/bash # timing the data entry # if read -t 5 -p "Please enter your name: " name then echo "Hello $name, welcome to my script" else echo echo "Sorry, too slow! " fi $ $ ./test25.sh Please enter your name: Rich Hello Rich, welcome to my script $ $ ./test25.sh Please enter your name: Sorry, too slow! $
也可以不对输入过程计时,而是让read命令来统计输入的字符数。当输入的字符达到预设 的字符数时,就自动退出,将输入的数据赋给变量。
本例中将-n选项和值1一起使用,告诉read命令在接受单个字符后退出。
只要按下单个字符 回答后,read命令就会接受输入并将它传给变量,无需按回车键。
$ cat test26.sh #!/bin/bash # getting just one character of input read -n1 -p "Do you want to continue [Y/N]? " answer case $answer in Y | y) echo echo "fine, continue on...";; N | n) echo echo OK, goodbye exit;; esac echo "This is the end of the script" $ $ ./test26.sh Do you want to continue [Y/N]? Y fine, continue on... This is the end of the script $ $ ./test26.sh Do you want to continue [Y/N]? n OK, goodbye $
隐藏方式读取
有时你需要从脚本用户处得到输入,但又在屏幕上显示输入信息。其中典型的例子就是输入 的密码,但除此之外还有很多其他需要隐藏的数据类型。
-s选项可以避免在read命令中输入的数据出现在显示器上(实际上,数据会被显示,只是 read命令会将文本颜色设成跟背景色一样)。这里有个在脚本中使用-s选项的例子。
$ cat test27.sh #!/bin/bash # hiding input data from the monitor read -s -p "Enter your password: " pass echo echo "Is your password really $pass? " $ $ ./test27.sh Enter your password: Is your password really T3st1ng? $
从文件中读取
最后,也可以用read命令来读取Linux系统上文件里保存的数据。每次调用read命令,它都 4 会从文件中读取一行文本。当文件中再没有内容时,read命令会退出并返回非零退出状态码。
其中最难的部分是将文件中的数据传给read命令。最常见的方法是对文件使用cat命令,将 结果通过管道直接传给含有read命令的while命令。下面的例子说明怎么处理。
while循环会持续通过read命令处理文件中的行,直到read命令以非零退出状态码退出。
$ cat test28.sh #!/bin/bash # reading data from a file count=1 cat test | while read line do echo "Line $count: $line" count=$[ $count + 1] done echo "Finished processing the file" $ $ cat test The quick brown dog jumps over the lazy fox. This is a test, this is only a test. O Romeo, Romeo! Wherefore art thou Romeo? $ $ ./test28.sh Line 1: The quick brown dog jumps over the lazy fox. Line 2: This is a test, this is only a test. Line 3: O Romeo, Romeo! Wherefore art thou Romeo? Finished processing the file $