linux-shell脚本入门

#!/bin/bash

# 调试脚本
# set -e # -e: 出现错误即停止执行 
# set +e # +e:任何错误都继续执行 
# set -x # 带+表示shell输出,即自己写的代码;不带+表示程序输出

# 变量
# 三种变量
# 局部变量,环境变量,shell变量(包含局部变量和环境变量)
your_name="黑胡椒" # =两边不能有空格!
echo $your_name
# 重新赋值
your_name="低调点"
echo "${your_name}"
# 删除变量
unset your_name
echo ${your_name} # 不存在不输出
# 常量
site="www.site.com"
echo "${site}"
readonly site
site="www.666.com" 
echo site
# 字符串
str1='test' # 单引号不转义
str2="demo" # 双引号内部变量会被解析,可以转义
# 字符串拼接,使用空格隔开。
echo $str1 $str2
# 字符串长度
echo ${#str1}
# 字符串子字符串
echo ${str1:1:3}
# 数组,不支持多维数组,成员用空格隔开
arr=('a' '1' '啊')
# 所有成员
echo "${arr[@]}"
echo "${arr[*]}"
# 数组长度
echo "${#arr[@]}"
# 数组循环
for item in "${arr[@]}"; do
  echo "${item}"
done
# 数组取值
echo "${arr[1]}"
# 单行注释
:<<`!`
多行注释
`!`
:<<``
多行注释
``
# 运算
# 1.关系运算符 -eq -ne -lt -gt -le -ge
# if
if [ 2 -gt 1 ]; then
   echo '2 > 1'
elif [ 1 -gt 0 ]; then
   echo '1 > 0'
else
   echo 'default'
fi
# 2.加减乘除,数字类型 `expr + - * / % == !=` 
a=1
b=2
echo `expr 2 + 2` # 需要加空格
echo $[a+b] # 下面两种都不需要加空格
echo $((a+b)) # 使用这种写法$((express))来替代`expr express`和$[express]
echo '====='
# [[]] 和 (()) 分别是[ ]的针对数学比较表达式和字符串表达式的加强版。
# 条件语句的三种写法:
# if [[ $a != 1 && $a != 2 ]]
# 如果不适用双括号:if [ $a -ne 1] && [ $a != 2 ]
# 或者:if [ $a -ne 1 -a $a != 2 ]
# (())中还可以使用 v++, v--, ++v, --v, ~v, v1**v2, v>>n, v<

# 原码	用最高位表示符号位,‘1’表示负号,‘0’表示正号。其他位存放该数的二进制的绝对值。
# 1 原码   0000 0001
# -1 原码  1000 0001
# 反码	正数的反码还是等于原码,负数的反码就是他的原码除符号位外,按位取反。
# 1 反码   0000 0001
# -1 反码  1111 1110
# 补码	正数的补码等于他的原码,负数的补码等于反码+1。
# 1 反码   0000 0001
# -1 反码  1111 1111

echo $((a++))
echo $((a--))
echo $((++a))
echo $((--a))
echo ${a}
echo $((~a))
echo $((2**3))
echo $((a<<1))
echo $((b>>1))
echo $((a&b))
echo $((a|b))

# 比较数字
if [ $a != $b ]
then
  echo 'a != b'
fi
b=1
if [ $a == $b ] 
then
  echo 'a == b'
fi
if [ `expr $a / $b` ]
then
  echo '能够整除'
fi
if [ `expr $a \* $b` ]; then
  echo `expr $a \* $b`
fi
# 3. 布尔运算 ! -o(或) -a(并且)
if [ 2 -gt 1 -o  0 -lt 1 ]; then
   echo 'ok'
fi
if [ `expr $a == 1` -a `expr $a % $b` -ge 0 ] 
then
  echo 'okk'
fi
# 4. 逻辑运算符 && || 同 -o -a
a=1
b=2
if [[ ! ${a} -ne 1 && ${b} -gt 1 ]] # 里面需要加一层[],并且和外层的[]之间不能有空格
then
  echo '取反'
fi
# 5. 字符串运算符 = != -z长度0返回true -n 长度不为0返回true
str=''
if [ -z "${str}" ]
then
  echo '为空'
fi
str='test'
if [ -n "${str}" ]
then
  echo '不为空'
fi

# 6. 文件测试运算符
:<<`!`
  -b file 块设备文件
  -c file 字符设备文件
  -d file 目录
  -f file 普通
  -p file 管道
  -r file 可读
  -w file 可写
  -x file 可执行
  -s file 文件是否不为空,大小为0
  -e file 文件或目录是否存在
  -S file 是否socket
  -L file 是否存在并且是一个符号链接
`!`
file='./base.sh'
if [ -w $file ]
then
  echo '可读'
fi
if [ -r $file ]
then 
  echo '可写'
fi
if [ -x $file ]
then 
  echo '可执行'
fi
if [ -L $file ]
then
  echo '存在并且是链接'
fi
if [ -f $file ]
then
  echo '是文件'
fi
dir='../demo-shell'
if [ -d $dir ]
then
echo '是目录'
fi
if [ ! -p $dir ]
then
echo '不是管道'
fi
if [ -s $file ]
then
  echo '文件不为空'
fi
if [ -e $file ]
then
  echo '文件存在'
fi
if [ -e $file -a -s $file -a -f $file ]
then
  echo '文件存在并且是内容不为空的普通文件'
fi
# echo 命令
# 输出到文件
echo 111 > ./test.txt
# 输出命令
echo `date`

# print 漂亮格式(略)

# test 数值,字符,文件测试(略)

# if 分支不能为空略)
# if语句经常和test语句结合使用

# 控制流程语句
# for 循环
for((i=0;i<3;i++));
do
  echo $i
done
# for 集合循环
for item in {a..c}; do
  echo "${item}"
done
# while 语句
a=3
while(($a >= 1))
do
  echo $a
  let 'a--'
  if [ $a -eq 0 ]
  then 
    echo 'boom'
  fi
done

# while read who
# do
#   echo "you like ${who}"
# done

# case ... esac
# 每个 case 分支用右圆括号开始,用两个分号 ;; 表示 break,即执行结束。
:<<``
while :
do
  echo "输入1到4之间的数字:"
  read aNum
  echo "你输入的数字为:${aNum}"
  case $aNum in
    1) echo '1';;
    2) echo '2';;
    3) echo '3';;
    4) echo '4';;
    6|7|8) 
      echo '6/7/8'
    ;;
    9) 
      echo '你猜中了'
      break # 跳出循环
    ;;
    *) 
      echo '其他数字'
    ;;
  esac
done
``
for((i=0;i<5;i++)); do
  if [ `expr $i % 2` -eq 0 ]
  then
    echo "${i}"
  else
    break
  fi
done

# 文件引用
# source ./func.sh
# .func.sh
# . ./func.sh # 被包含文件不需要可执行权限

# 输入/输出重定向

# 输出重定向到file
echo 'hello' > test.txt

# 追加内容到文件
echo 'world' >> test.txt

# 输入重定向,读取文件行数
# echo "$(wc -l test.txt)" # 输出带了文件名
# echo "$(wc -l < test.txt)"

# 重定向输入,再重定向输出
wc -l < test.txt > lineNumber.txt # 2

# 重定向错误信息
# echo 2> err.txt

# 追加信息
# echo 2>> err.txt

# 将输出和错误一起输出到文件
echo 'error info' > err.txt 2>&1

# Here Document

wc -l << EOF
  hello
  world
  shell
EOF

ls << EOF
-al
EOF

# 执行后丢弃到垃圾箱
echo 'ls -al' > /dev/null

# 丢弃错误信息
echo 'ls -al' > /dev/null 2>&1

# 总结
# ${x}:变量,${val}, ${arr[*]}
# ${#x}:长度,${#str},${#arr[@]}
# 多行注释是<<,可以理解为不输出,`>`为输出到...。
# if的elseif是写作elif, if [];后面的`then`别忘了。
# `do... done`代替`{}``,比如while() do...done, for() do...done
# 语句反写来代表结束,if...fi case...esac。
# case 中比较特殊,`;;`替代`break``)`替代`:`
# if判断中,多个条件语句怎么写?`[[xx && xx]]` `[xx -a xx -o xx]` `[xx] && [xx]`
# 数字比较可以使用==, !=。或者使用-eq -ne。没有<=,>=。需使用-ge,-le代替
# 使用$((express)),来获取表达式的结果作为变量使用。

# 其他注意的地方:
# 1. 命令替换
# `ls /etc` : 反引号 (所有的unix系统都支持)
# $(ls /etc) : $+() (部分unix系统不支持)
# 多个嵌套使用时,从内向外执行。

fun.sh文件

#!/bin/bash
# 函数
# 所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分,
# 直至shell解释器首次发现它时,才可以使用。调用函数仅使用其函数名即可
# return 值只能是 [0-255] 范围
function add () {
  echo "请输入两个值来进行数字相加..."
  echo "输入第一个数字:"
  read a
  echo "输入第二个数字:"
  read b
  return $(($a + $b))
}

# add
# echo "两个数字相加的值为:$?" # 调用函数后通过$?来获取

# 仅对其上一条指令负责,一旦函数返回后其返回值没有立即保存入参数,那么其返回值将不再能通过 $? 获得。
echo "$?拿不到了" # $?为0,表示上一次执行的echo结果没有出错。每次输出(echo/返回值也是输出)的结果都会覆盖上次输出(或者函数调用返回值)的结果。

function fnParam() {
  echo "第1个参数$1"
  echo "第2个参数$2"
  echo "第10个参数 $10 " # 变成拼接了
  echo "第10个参数${10}"
  echo "第11个参数${11}"
  echo "共有参数个数为:$#"
  echo "所有参数字符串输出:$*"
  echo "当前进程ID $$"
  echo "后台运行的最后一个进程ID $!"
  a=$@
  echo "所有参数: ${a}"
  echo "退出命令的状态$?" # 0表示没有出错,其他表示出错状态
}
fnParam 0 1 2 3 4 5 6 7 8 22 99
# 注意,$10 不能获取第十个参数,获取第十个参数需要${10}。当n>=10时,需要使用${n}来获取参数。
b='外部变量'
function fnVal () {
  local b='本地变量'
  echo "${b}"
}
echo "\$b=${b}"
fnVal

你可能感兴趣的:(shell,linux,bash,运维)