shell

linux下的shell脚本

Shell 基本运算符

Zsh和Bash的兼容性问题

The Uses of the Exec Command in Shell Script

Shell

示例:
wget http://soft.vpser.net/lnmp/lnmp1.8-full.tar.gz
(lnmp下载地址:https://lnmp.org/download.html)

#!/bin/sh
#!/bin/bash
sh是早期linux shell, bash是为GNU编写的unix shell, 兼容sh
sh遵循posix规范,代码出错时,不再往下运行; bash 代码出错,还将继续运行

查看当着shell
echo $SHELL

查看已安装的shell
cat /etc/shell

切换shell
chsh -s /bin/bash
chsh -s /bin/zsh

bash与zsh的区别
bash读取 ~/bash_profile
zsh 读取 ~/zshrc
!.注意空格和引号
2.注意数组index不同
3.使用一个等号,避免使用短if语句

Bash

参数缺省值
${1-} ${1:-2}
${parameter-default}, ${parameter:-default}
If parameter not set, use default.

左移参数
while [ $# -ne 0 ]; do
    if [ $1 == 'install' ]; then
        break
    fi
    shift
done
   
1>/dev/null 2>&1的含义 
command printf %s\\n "Failed mark .nvm/nvm_exec as excutable" >&2  #输出标准错误信息

> 代表重定向到哪里
0 表示键盘输入(stdin)
1 表示stdout标准输出,系统默认值是1,所以">/dev/null"等同于"1>/dev/null" 
2 表示stderr标准错误 
& 表示等同于的意思,2>&1,表示2的输出重定向等同于1 


EOF用法:
case "$i" in
-d*) options=$options" --debug";;
-v*) VERBOSE="true";;
-h*) DRYRUN="true"; cat <<EOF
Usage: config [options]
 -d	Build with debugging when possible.
 -v	Verbose mode, show the exact Configure call that is being made.
 -h	This help.
EOF
;;
esac

带变量多行显示
echo /usr/bin/env \
 __CNF_CPPDEFINES="'$__CNF_CPPDEFINES'" \
 __CNF_CPPINCLUDES="'$__CNF_CPPINCLUDES'" \
 $PERL $THERE/Configure $OUT $options
 
布尔:
= and == are for string comparisons
-eq is for numeric comparisons

$ a=foo
$ [ "$a" = foo ]; echo "$?"       # POSIX sh
0
$ [ "$a" == foo ]; echo "$?"      # bash-specific
0
$ [ "$a" -eq foo ]; echo "$?"     # wrong
-bash: [: foo: integer expression expected
2

显示进度(echo -e 转义 -n 不换行)
echo -ne '#####                     (33%)\r'
sleep 1
echo -ne '#############             (66%)\r'
sleep 1
echo -ne '#######################   (100%)\r'
echo -ne '\n'

表格格式化列数据
column -t < a.dat > a.txt

exec命令
$ bash
$ exec > file
$ date
$ exit
$ cat file
Thu 18 Sep 2014 23:56:25 CEST

命令行

$0 :即命令本身,相当于c/c++中的argv[0]
$1 :第一个参数. $2, $3, $4 ... :第2、3、4个参数,依次类推。
$# :参数的个数,不包括命令本身
$@ :参数本身的列表,也不包括命令本身
$* :"$*"将所有的参数解释成一个字符串,而"$@"是一个参数数组。
$$ :当前shell进程ID
$? :获取上一个命令的退出状态

$() ``(反引号)作命令行使用
${} 变量边界, $var和${var}相同,
$[] $(()) 进行整数数学计算; $[a+b*c%d]
[] 测试, [ -f /etc/bashrc ], 括号内要加空格
(()) 符合C语言规则, ((i++))  for((i=0;i<10;i++ ))
[[]] 参数扩展和命令替换, [[ $res=~'hello' ]]

数组:
arr=(1,2,3,4,5)
for i in ${arr[@])
do
    echo $i
    if [ $i -lt 4 ]: then
        continue
    fi
    echo '----'
done

数组长度:
arrLen=${#arr[@]}
删除数组:
unset arr[1]
关联数组:
declare -A site;
site["google"]="www.google.com"
site["runoob"]="www.runoob.com"
site["taobao"]="www.taobao.com"
或:
declare -A site(["google"]="www.google.com" ["runoob"]="www.runoob.com" ["runoob"]="www.runoob.com")

eval函数
pip="|"
eval ls $pipe wc -l  #二次扫描

eval echo \$$#       #显示最后一个参数,第一次扫描$#为参数个数

指针作用
x=100
ptr=x
eval echo $ptr
eval $ptr=60
echo $x             #显示60

语法

if [ -f /etc/resolv.conf ];then
    echo "$FILE exist"
else
    echo "$FILE does not exist"
fi
等价于:
[ -f /etc/resolv.conf ] && echo "$FILE exist" || echo "$FILE does not exist"

执行多个命令:
[ -f /etc/resolv.conf ] && (echo "$FILE exist"; cp "$FILE" /tmp/;)

判断文件可执行:
[ -x /etc/resolv.conf ] && echo "$FILE can excute"

function test()
{
    echo 'input param1: '$1
    echo 'input param1: '$2
    return 100                   #返回值必须是数值
}
运行:
test hello world
echo "test return value is: "$?
res=$(test 'hello' 'world')                  #读取echo返回值
echo "test 'hello' 'world' return is --> "$res
if [[ $res =~ 'hello' ]]; then
    echo 'output having "hello"'
fi
输出:
input param1: hello
input param1: world
test return value is: 100
test 'hello' 'world' return is --> input param1: hello input param2 is: world
output having "hello"

for a in {1..10}
do
    echo $a
done

for file in ${ls ~/} 
do 
    echo $file 
done

函数内局部变量
local EACH_PROFILE
for EACH_PROFILE in ".bashrc" ".bash_profile" ".zprofile" ".zshrc"
do
    echo $EACH_PROFILE
done

a=1
while ((a<9))
do
    echo $i
    let i++
done

while read line
do
    echo $line
done < ~/.ssh/config

read -p "Continue? (Y/N): " confirm && [[ $confirm == [yY] || $confirm == [yY][eE][sS] ]] || exit 1

read -p "choice yes/no: " yes
case $yes in
    y)
        echo 'choice Y'
        ;;
    n|c)
        echo 'choice N'
        ;;
    *)
        echo 'choice unknown'
        ;;
esac

read -p "Continue? (Y/N): " confirm && [[ $confirm == [yY] || $confirm == [yY][eE][sS] ]] && (echo "ok!"; echo "exit...") || exit 1

read -p "Reboot now? (Y/N): " confirm
if [[ $confirm == [yY] || $confirm == [yY][eE][sS] ]]; then
    reboot now
elif [[ $confirm == [cC] ]]: then
    exit 1
fi

检测是否安装
type python >/dev/null 2>&1
echo $?
if ! type python >/dev/null 2>&1; then
    echo 'python no installed!'
fi

检测命令是否执行成功
if [ $? -eq 0 ]; then
    echo 'execute success'
else
    echo 'execute error'
fi

字符串

#删除左边字符,保留右边的字符
%删除右边字符,保留左边的字符
str="http://www.baidu.com/123.html"
echo ${str#$*//}        #www.baidu.com/123.html
echo ${str##*/}         #123.html
echo ${str%/*}          #http://www.baidu.com
echo ${str%%/*}         #http:
echo ${str:0:5}         #http:
echo ${str:7}           #www.baidu.com/123.html
echo ${str:0-8:3}       #123
echo ${str:0-8}         #123.html

name="shell"
url="http://www.baidu.com"
str1=$name$url                          #中间不能有空格
str2="$name $url"                       #如果被双引号包围,那么中间可以有空格
str3=$name": "$url                      #中间可以出现别的字符串
str4="$name: $url"                      #这样写也可以
str5="${name}Script: ${url}index.html"

echo $str1                              #shellhttp://www.baidu.com
echo $str2                              #shell http://www.baidu.com
echo $str3                              #shell:http://www.baidu.com

文件属性

if [ -f $file ]: then
    rm $file
fi
if [ ! -d $path ]: then
    mkdir $path
fi

-e 判断对象是否存在
-d 判断对象是否存在,并且为目录
-f 判断对象是否存在,并且为常规文件
-L 判断对象是否存在,并且为符号链接
-h 判断对象是否存在,并且为软链接
-s 判断对象是否存在,并且长度不为0
-r 判断对象是否存在,并且可读
-w 判断对象是否存在,并且可写
-x 判断对象是否存在,并且可执行
-O 判断对象是否存在,并且属于当前用户
-G 判断对象是否存在,并且属于当前用户组
-nt 判断file1是否比file2新  [ "/data/file1" -nt "/data/file2" ]
-ot 判断file1是否比file2旧  [ "/data/file1" -ot "/data/file2" ]


常见的环境变量:
PATH: 决定了shell将到哪些目录中寻找命令或程序
ROOTPATH: 这个变量的功能和PATH相同,但它只罗列出超级用户(root)键入命令时所需检查的目录
HOME: 当前用户主目录
USER: 查看当前的用户
LOGNAME: 查看当前用户的登录名。
UID: 当前用户的识别字,取值是由数位构成的字串。
SHELL: 是指当前用户用的是哪种Shell。
TERM: 终端的类型
PWD: 当前工作目录的绝对路径名
MAIL: 是指当前用户的邮件存放目录:
HISTSIZE: 是指保存历史命令记录的条数
HOSTNAME: 是指主机的名称
PS1: 是基本提示符,对于root用户是#,对于普通用户是$
PS2: 是附属提示符,默认是">”。
IFS: 输入域分隔符。当shell读取输入时,用来分隔单词的一组字符,它们通常是空格、制表符和换行符
参数 说明 示例
-eq 等于则为真 if [ $var1 -eq 100 ]
-ne 不等于则为真 if [ $var1 -ne 100 ]
-gt 大于则为真 if [ $var1 -gt 100 ]
-ge 大于等于则为真 if [ $var1 -ge 100 ]
-lt 小于则为真 if [ $var1 -lt 100 ]
-le 小于等于则为真 if [ $var1 -le 100 ]
== 相等则为真 if [ \(var1 == \)var2 ]
!= 不相等则为真 if [ \(var1 != \)var2 ]
=~ 前边变量包含后边变量则为真 if [ \(var1 =~ \)var2 ]
-z 字符串 字符串的长度为零则为真 if [ -z $var1 ]
-n 字符串 字符串的长度不为零则为真 if [ -n $var1 ]