Linux 笔记--脚本
脚本的参数
参数变量
$* | 传递给脚本/函数的所有参数(把所有参数当成一个字符串) |
$@ | 参数名字 |
$0 | 文件名字(first.sh…) |
$# | 总共有多少个参数 |
$$ | 脚本的 PID |
$! | 上一个被执行的命令的 PID(后台运行的进程) |
IFS=, # 将函数参数的分隔符改成用‘,‘ 例如 IFS=:
var=test echo ${#var} 4 echo $#var 0var echo $# == 0
# 2014-10-16 16:21:41 ## 测试 $* 和 $# 的区别 function countargs { echo $# args; } countargs "$*" countargs "$@" ## 将上面的代码保存为一个文件, sh FILENAME a b c ## 3 args ## 1 args
使用默认参数
${varname:-word} | 如果 varname 为 null,返回 word, (${count:-0}) |
${varname:+word} | 如果 varname 为 null,返回 null,否则返回 word,测试一个变量的存在性.${count:+1}返回 1,即‘true‘ |
${varname:=word} | 如果 varname 为 null,将其设置为 word, 不能设置位置参数和特殊参数 |
${varname:?message} | 如果 varname 为 null,打印 varname:后跟信息 message,并退出当前命令或脚本,捕获为定义变量导致的错误 |
${varname:NUM | 返回从 NUM 开始的字符串, 开头以 0 计算 |
${varname:NUM:LENG | 返回从 NUM 开始的 LENG 长度字符串 |
count=frogfotman ${count:4} 返回 footman ${count:4:4} 返回 foot sort -nr $1 | head -${2:-10} # the first version # 当后面没有接文件的时候, 会有一些奇怪的信息 filename=${1:?"filename missing"} howmany=${2:-10} sort -nr $filename | head -$howmany # the second version # 当后面没有接文件的时候, 输出的错误信息有点不尽人意 filename=$1 filename=${filename:?"filename missing."} howmany=${2:-10} sort -nr $filename | head -$howmany # the third version filename=$1 filename=${filename:?"filename missing."} howmany=${2:=1} sort -nr $filename | head -$howmany # the fourth version # 会把 1 赋值给 $2, shell 会提示出错, "cannot assign in this way" filename=$1 filename=${filename:?"filename missing"} howmany=$2 sort -nr $filename | head -${howmany:=10} # the fifth version filename=$1 filename=${filename:?"filename missing"} howmany=$3 header=$2 echo -e -n ${header:+"ablums artist\n"} # 如果变量为空什么都不输出, 连空行也不输出, 如果不为空就输出 # echo $head # 的值不是后面的字符串...注意区分,他只是返回 sort -nr $filename | head -${howmany:=3}
getopts
while getopts ":ab:c" opt; do case $opt in a) echo ‘this is a‘ ;; b) echo ‘this is b‘ echo "args b is $OPTARG" ;; c) echo ‘this is c‘ ;; \?) echo ‘usage: alice [-a][-b bargs] [-c] args...‘ exit 1;; esac done echo $OPTIND shift $(($OPTIND - 1)) # 输入: ./my.sh -a -a -b # 输出: # this is a # this is b # 4 # 输入: ./my.sh -a -b 5 -c # 输出: # this is a # this is b # args b is 5 # this is c # 5 # 输入: ./my.sh -acb 4 # this is a # this is c # this is b # args b is 4 # 3
数组
name[0]=abc; name[1]=def; name[2]=ghi; ## == name=(abc def ghi) ## == name=([0]=abc [1]=def [2]=ghi) for i in "${name[@]}"; do echo $i done
文件描述符
<> FILE: 文件作为输入和输出 2> FILE: 将错误写入文件 或者 2>>FILE &> FILE: 定向标准输出和标准错误到 FILE 或者 &>>FILE 2>&1: 把 2 输出到 1 2<&0: 把 2 出入到 0
模式匹配
${VALUE#pattern} | 匹配以 pattern 开头的部分,只匹配一次 |
${VALUE##pattern} | 匹配以 pattern 开头的部分,匹配至多次 |
${VALUE%pattern} | 匹配以 pattern 结尾的部分,只匹配一次 |
${VALUE%%pattern} | 匹配以 pattern 结尾的部分,匹配至多次 |
${VALUE/OLDSTRING/NEWSTRING} | 替换字符串,只替换一个匹配到 |
${VALUE//OLDSTRING/NEWSTRING} | 替换字符串,替换全部匹配到 |
# 从前面开始往后面删除匹配到的, 留下最后没被匹配的 % 从后面往前面开始删除, 留下前面的
temp=/home/sunx/Work/bin echo ${temp#*/} # home/sunx/Work/bin echo ${temp%%/*} # echo ${temp##*/} # bin echo ${temp%/*} # /home/sunx/Work/bin temp=test.c file1=${temp#*\.} echo ${file1} # c file2=${temp%*\.*} # test temp=test.c.cpp file=${temp#*\.} # c.cpp file=${temp##*\.} # cpp file=${temp%\.*} # test.c file=${temp%%\.*} #
脚本控制流
test
文件属性
-e | 该名字是否存在 |
-f | 该名字是否存在且为档案 file |
-d | 改名字是否存在且为目录 dirctory |
-b | 该名字是否存在且为 block device 装置 |
-c | 该名字是否存在且为 charcter device |
-S | 该名字是否存在且为 socket 档案 |
-p | 该名字是否存在且为 FIFO(pipe) 档案 |
-L | 该当名是否存在且为一个 link 档案 |
文件权限
-r | 是否可读 |
-w | 是否可写 |
-x | 是否可执行 |
2 个文件比较
-nt | (newer than)file1 是否比 file2 新 |
-ot | (older than)file1 是否比 file2 旧 |
-ef | 是否相等, 判断 hard link 经常使用 |
2 个数值比较
-eq | 是否相等 |
-ne | not equal |
-gt | (greater than)大于 |
-lt | (less than) 小于 |
-ge | (greater than or equal) 大于等于 |
-le | (less than or equal) 小于等于 |
字符串
test -z string | 判定字符串是否为 0? 若 string 为空字符串, 则是 true |
test -n string | 判定字符串是否非 0? |
test str1 = str2 | 判定 str1 是否等于 str2 |
test str1 != str2 | 判定是否不等,一定要加空格 |
test 中使用逻辑判断
-a | test -r file -a -x file | |
-o | test -r file -o -x file | |
! | test ! -x file, 当 file 不具有 x 权限时, 才是 true |
[] 判断
[] 等价于 test
[ "$HOME" == "$MAIL" ] # 在 bash 里面用 = 和用 == 是一样的 # [ ] 前后都要加空格 read -p "Please input (Y/N): " yn [ "$yn" == "Y" -o "$yn" == "y" ] && echo "OK, continue" && exit 0 [ "$yn" == "N" -o "$yn" == "n" ] && echo "Oh, interrupt!" && exit 0 echo "I don‘t know what your choice is" && exit 0 [ "$yn" == "Y" -o "$yn" == "y" ] # 等价于 [ "$yn" == "Y" ] || [ "$yn" == "y"]
if 语句
if [ 条件判断式 ]; then ... fi read -p "please input(Y/N):" yn if [ "$yn" == "Y" ]||[ "$yn" == "y" ]; then echo "ok, yes continue" exit 0 fi if [ 条件判断式 ]; then ... else ... fi if [ 条件判断式 ]; then ... elif [ 条件判断式二 ]; then ... else ... fi
for
for animal in dog cat elephant; do echo "there are ${animal}s..." done # dogs # cats # elephants users=$(cut -d ‘:‘ -f1 /etc/passwd) # users=`cut -d ‘:‘ -f1 /etc/passwd` for usename in $users; do id $username finger $username done
# $((...)) 对数学表达式求值 # echo $((2*10)) 20 # echo $((2**3)) 8 # echo $((s)) # 结果是 0, 说明这样的操作 shell 会自动给他 0,接下来看下面 for((i=0; i<=10; ++i)) do s=$(($s+$i)) # s = s + i done
while
while [ "$yn" != "yes" -a "$yn" != "YES" ]; do read -p "please input yes/YES to stop this program: " yn done echo "ok! you input the correct answer."
until
until [ "$yn" == "yes" -o "$yn" == "YES" ]; do read -p "please input yes/YES to stop this program: " yn done echo "ok! you input the correct answer." # 直到条件满足才退出循环.
case
case $1 in "hello") echo "hello, how are you?" ;; "") echo "you must input parameters, example: {$0 someword}" ;; *) # 相当于 C 语言的 default echo "usae $0 {hello}" ;; # 也可以在 case 里面用 | 來表示或, 例如 case $1 in 123 | 456) ... esac # end
select
select name in LIST; do ... done temp=$(ls *.c) # a.c b.c select file in $temp; do if [ $file == "a.c" ]; then echo "a.c"; fi if [ $file == "b.c" ]; then echo "b.c"; fi done 1) a.c 2) b.c #? 1 a.c #? 2 b.c #? 3 bash: [: ==: unary operator expected bash: [: ==: unary operator expected #? 1 a.c #?
脚本函数
如果从别的文件中调用函数, 例文件名字是 a.sh
. /PATH_TO/a.sh 或者是 source ./PATH_TO/a.sh
function FUNCTNAME() { } FUNCTNAMENAME() { } ## 这 2 种形式都是可以声明和定义一个函数的 unset -f FUNCTNAME
function afunc { echo in function : $0 $1 $2 var1="in function" echo var1: $var1 } var1="outside function" echo var1: $var1 echo $0: $1 $2 afunc funcarg1 funcarg2 echo var1: $var1 echo $0: $1 $2 # var1: outside function # ./Function.sh: arg1 arg2 # in function : ./Function.sh funcarg1 funcarg2 # 从这里开始调用函数 # var1: in function # var1: in function # var1 还是 in function # ./Function.sh: arg1 arg2
function afunc { # local var1 echo in function : $0 $1 $2 # var1="in function" # 如果这句话被注释掉, 下面以行的 var1 的值就变成了空, 但是如果同时把 local 的声明也注释掉就是 outside... echo var1: $var1 } # 由上面的注释可以知道, 再脚本里面定义的变量可以在函数里面使用, 但是如果函数定义了该变量就不行了 var1="outside function" echo var1: $var1 echo $0: $1 $2 afunc funcarg1 funcarg2 echo var1: $var1 echo $0: $1 $2 # var1: outside function # ./Function.sh: arg1 arg2 # in function : ./Function.sh funcarg1 funcarg2 # var1: in function # var1: outside function # var1 的值还是函数的, 函数外的 var1 的值没有影响 # ./Function.sh: arg1 arg2
function printit() { echo -n "Your choice is $1" } echo "This program will print your selection !" case $1 in "one") printit; echo $1 | tr ‘a-z‘ ‘A-Z‘ # 将参数做大小写转换! ;; "two") printit; echo $1 | tr ‘a-z‘ ‘A-Z‘ ;; "three") printit; echo $1 | tr ‘a-z‘ ‘A-Z‘ ;; *) echo "Usage $0 {one|two|three}" ;; esac ##############上面是程序的的参数, ..区别于函数的的参数. .........############### ## 程序的参数是在 shell 命令中跟在脚本名字后面的, 函数的参数是在脚本里面调用函数时候, 跟在脚本后面的 ################下面是函数的参数, ..区别于程序的参数. .........################# function printit() { echo -n "Your choice is $1 " echo "This program will print your selection !" case $1 in "one") printit 1; echo $1 | tr ‘a-z‘ ‘A-Z‘ # 将参数做大小写转换! ;; "two") printit 2; echo $1 | tr ‘a-z‘ ‘A-Z‘ ;; "three") printit 3; echo $1 | tr ‘a-z‘ ‘A-Z‘ ;; *) echo "Usage $0 {one|two|three}" ;; esac } printit one # result # Your choice is one This program will print your selection ! # Your choice is 1 This program will print your selection ! # 注意 printit 1 也会继续调用函数 # Usage a.sh {one|two|three} # ONE
脚本调试
sh [-nvx] FILE
-n | 不执行,仅检查语法问题 |
-v | 执行前,先输出脚本 |
-x | 将使用到的脚本输出 |
cat a.sh echo "hello" || echo "123" sh -n a.sh # 检查语法问题, 没输出,说明没问题,似乎没用 :D sh -v a.sh echo "hello" || echo "123" hello sh -x a.sh + echo hello hello
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。