首页 > 代码库 > LinuxShell脚本攻略--第一章

LinuxShell脚本攻略--第一章

使用 shell 进行数学运算:

#!/bin/bash
no1=4;
no2=5;

let result=no1+no2
echo $result

result=$[ $no1 + no2 ]

result=$(( no1 + 50 ))

result=`expr 3 + 4`
result=$(expr $no1 + 5)

echo "4 * 0.56" | bc
result=`echo "$no * 1.5" | bc`
echo $result

echo "scale=2;3/8" | bc        #0.37
no=100
echo "obase=2;$no" | bc
no=1100100
echo "obase=10;ibase=2;$no" | bc

将错误信息重定向到文件:

cmd 2>stderr.txt 1>stdout.txt    #stderr 单独重定向到一个文件,将 stdout 重定向到另一个文件
cmd &> output.txt    #还可以利用更好的方法将 stderr 转换成 stdout ,使得 stderr 和 stdout都被重定向到同一个文件中

tee 既可以将数据重定向到文件,还可以提供一份重定向数据的副本作为后续命令的 stdin 。在下面的代码中, tee 命令接收到来自 stdin 的数据。它将 stdout 的一份副本写入文件out.txt,同时将另一份副本作为后续命令的 stdin 。命令 cat -n 将从 stdin 中接收到的每一行数据前加上行号并写入 stdout

$ cat a* | tee out.txt | cat -n
cat: a1: Permission denied
     1    a
     2    a
     3    a
     4    a
     5    a

 $ cat out.txt
  a1
  a1

注意, cat: a1: Permission denied 并没有在文件内容中出现。这是因为这些信息属于 stderr ,而 tee 只能从 stdin 中读取.默认情况下, tee 命令会将文件覆盖,但它提供了一个 -a 选项,用于追加内容.如: $ cat a* | tee -a out.txt | cat –n 。
我们可以使用stdin所谓命令参数。只需要将-作为命令的文件名参数即可:$ cmd1 | cmd2 | cmd -

$ echo who is this | tee -
who is this
who is this

重定向时 

> 等同于 1> ;对于 >> 来说,情况也类似(即 >> 等同于 1>> )。处理错误时,来自 stderr 的输出被丢弃到文件/dev/null中。/dev/null是一个特殊的设备文件,它接收到的任何数据都会被丢弃。null设备通常也被称为黑洞,因为凡是到这儿的数据都将一去不返。

有时需要对文本块(多行文本)进行重定向,就像对标准输入做的那样。考虑一个特殊情况:源文本就位于shell脚本中。一个实用的例子是向log文件中写入头部数据。
a.sh

#!/bin/bash
cat<<EOF>log.txt
LOG FILE HEADER
This is a test log file
Function: System statistics
EOF

在 cat <<EOF>log.txt 与下一个 EOF 行之间的所有文本行都会被当做 stdin 数据.

 数组

#!/bin/bash
arr=(f z k b a)      #很多种方式创建数组
array_var[0]="test1"
array_var[1]="test2"

echo ${arr[2]}
echo ${array_var[0]}
echo ${#arr[*]}           #获取数组的长度

declare -A fruits_value      #定义关联数组
fruits_value=([apple]=100dollars [orange]=150 dollars)
echo ${fruits_value[apple]}  
echo ${!fruits_value[*]}      #获取数组的每个索引值,也可以用下面的方法   orange apple
echo ${!fruits_value[@]}

别名:

alias install=‘sudo apt-get install‘ 就可以用install代替命令。但这样关闭终端就会消失,可以在~/.bashrc中:echo ‘alias cmd="command seq"‘ >> ~/.bashrc。如果需要删除别名,只用将其对应的语句(如果有的话)从 ~/.bashrc 中删除,或者使用 unalias 命令。或者使用 alias example= ,这会取消名为 example的别名。有些时候在我们建了别名的时候在使用命令时不想使用别名而是想使用原来的命令,在命令前加上\,像:\command

日期:              日期内容

星期              %a(例如:Sat)
                %A(例如:Saturday)
月                 %b(例如:Nov)
                %B(例如:November)
日                 %d(例如:31)
固定格式日期(mm/dd/yy)       %D(例如:10/18/10)
年                 %y(例如:10)
                  %Y(例如:2010)
小时                %I或%H(例如:08)
分钟                %M(例如:33)
秒                 %S(例如:10)
纳秒                   %N(例如:695208515)
Unix纪元时(以秒为单位)        %s(例如:1290049486)

$ date +%s
1481029113
$ date --date "Thu Nov 18 08:07:21 IST 2010" +%s
1290047841
$ date --date "Jan 20 2001" +%A
Saturday
$date "+%d %B %Y"
06 十二月 2016

函数:

函数声明:

function fname(){
    statements;
}
或者:
fname(){
    statements;
}
调用:
fname arg1 arg2 ; #传递参数

? $1 是第一个参数。
? $2 是第二个参数。
? $n 是第n个参数。
? "$@" 被扩展成 "$1" "$2" "$3" 等。
? "$*" 被扩展成 "$1c$2c$3" ,其中 c 是IFS的第一个字符。
? "$@" 要比 "$*" 用得多。由于 "$*" 将所有的参数当做单个字符串,因此它很少被使用
$? 用来代替上一个指令的返回值。

开启一个子shell:用(),在()中写子shell的代码

read命令:

(1) 下面的语句从输入中读取n个字符并存入变量 variable_name :
read -n number_of_chars variable_name
例如:
$ read -n 2 var
$ echo $var

(2) 用无回显的方式读取密码:
read -s var
(3) 显示提示信息:
read -p "Enter input:"  var
(4) 在特定时限内读取输入:
read -t timeout var
例如:
$ read -t 2 var   #在2秒内将键入的字符串读入变量var
(5) 用特定的定界符作为输入行的结束:
read -d delim_char var
例如:
$ read -d ":" var
hello:  #var 被设置为 hello

书中有个例子,运行命令直至成功

repeat() { while true; do $@ && return; done }

在大多数现代系统中, true 是作为/bin中的一个二进制文件来实现的。这就意味着每执行一次 while 循环,shell就不得不生成一个进程。如果不想这样,可以使用shell内建的“ : ”命令,它总是会返回为0的退出码:

repeat() { while :; do $@ && return; done }

这里记住ture和:的区别就可以了。
用上面那个脚本的可能环境是下载一个文件的时候:repeat wget -c http://www.example.com/software-0.1.tar.gz

for 循环:

for var in list;  #echo {1..50} 能够生成一个从1~50的数字列表
do
  commands; 
done

for 循环也可以采用C语言中 for 循环的格式。例如:

for((i=0;i<10;i++)){
  commands; #使用变量$i
}

 

while 循环

while condition
do
  commands;
done

util循环

x=0;
until [ $x -eq 9 ];
do
  let x++; echo $x;
done

比较:

if condition;
then
    commands;
else if condition; 
then
    commands;
else
    commands;
fi

这里有一个技巧:if 和 else 语句可以进行嵌套。 if 的条件判断部分可能会变得很长,但可以用逻辑运算符将它变得简洁一些:
  [ condition ] && action; # 如果 condition 为真,则执行 action ;
  [ condition ] || action; # 如果 condition 为假,则执行 action 。
&& 是逻辑与运算符, || 是逻辑或运算符。编写Bash脚本时,这是一个很有用的技巧。

算术比较
条件通常被放置在封闭的中括号内。一定要注意在 [ 或 ] 与操作数之间有一个空格。如果忘记了这个空格,脚本就会报错。例如:
[$var -eq 0 ] or [ $var -eq 0]    #这个是错误的 因为第一个$var 前和第二个 0的后没有空格
对变量或值进行算术条件判断:
[ $var -eq 0 ] #当 $var 等于 0 时,返回真
[ $var -ne 0 ] #当 $var 为非 0 时,返回真
其他重要的操作符如下所示。
-gt :大于。
-lt :小于。
-ge :大于或等于。
-le :小于或等于。
可以按照下面的方法结合多个条件进行测试:
[ $var1 -ne 0 -a $var2 -gt 2 ] #使用逻辑与-a
[ $var1 -ne 0 -o var2 -gt 2 ] #逻辑或 -o

字符串比较:

使用字符串比较时,最好用双中括号,因为有时候采用单个中括号会产生错误,所以最好避开它们。
[[ $str1 = $str2 ]] :当 str1 等于 str2 时,返回真。也就是说, str1 和 str2 包含的文本是一模一样的。
[[ $str1 == $str2 ]] :这是检查字符串是否相等的另一种写法。也可以检查两个字符串是否不同。
[[ $str1 != $str2 ]] :如果 str1 和 str2 不相同,则返回真。我们还可以检查字符串的字母序情况,具体如下所示。
[[ $str1 > $str2 ]] :如果 str1 的字母序比 str2 大,则返回真。
[[ $str1 < $str2 ]] :如果 str1 的字母序比 str2 小,则返回真。
[[ -z $str1 ]] :如果 str1 包含的是空字符串,则返回真。
[[ -n $str1 ]] :如果 str1 包含的是非空字符串,则返回真。
注意在 = 前后各有一个空格。如果忘记加空格,那就不是比较关系了,而变成了赋值语句。

文件系统相关测试
[ -f $file_var ] :如果给定的变量包含正常的文件路径或文件名,则返回真。
[ -x $var ] :如果给定的变量包含的文件可执行,则返回真。
[ -d $var ] :如果给定的变量包含的是目录,则返回真。
[ -e $var ] :如果给定的变量包含的文件存在,则返回真。
[ -c $var ] :如果给定的变量包含的是一个字符设备文件的路径,则返回真。
[ -b $var ] :如果给定的变量包含的是一个块设备文件的路径,则返回真。
[ -w $var ] :如果给定的变量包含的文件可写,则返回真。
[ -r $var ] :如果给定的变量包含的文件可读,则返回真。
[ -L $var ] :如果给定的变量包含的是一个符号链接,则返回真。

LinuxShell脚本攻略--第一章