Bash 快速入门

基础知识

三级权限

目录的写权限是写入目录表的权限,例如文件的创建和删除、更名。写入目录下的文件,不需要目录的写权限。

目录有执行权限意味着 分析路径名 过程中可检索该目录,例如 cat /a/b/c ,则 /a /a/b 需要有 x 权限,c 需要有 r 权限。

Sticky (t) 权限:文件而言目前没有用。但若目录有 wt 权限,则只能被文件主删除。

权限验证过程:进程的主、组属性与文件的主、组属性比较。root 不受上述限制。

umask 用于设置初始权限。umask 022 可放到 bash 文件中,只在此文件生效。

SUID 权限

实际 UID 和有效 UID:后者是用来进行权限判断的 UID。

chmod u+s query

SUID 使得用户可以通过文件主提供的程序,以文件主的权限访问文件,但这种访问依赖于文件主提供的程序,进行有限的访问

shell 的启动形式

  • Login Shell:通过登录启动的 Shell
    • 执行 profile 文件。/etc/profile ~/.bash_profile ~/.bash_login ~/.profile
    • 推出之执行 logout 文件。
  • Interactive Shell:交互式解释器的 Shell。通过输入命令回车可得到命令结果
    • 执行 $HOME/.bashrc
  • Non Interactive Shell:通过 bash scriptname 执行的脚本

BASH 的执行形式

  • Fork 执行
    • bash < cmd
    • bash cmd
    • bash -x cmd
    • bash cmd args
  • Execve 执行
    • . cmd args

重定向

stdin 的 fd = 0

输入

  • sort < file 将 file 定向为 sort 的 stdin

  • 使用定界符:

    cat << TOAST
    * Now : `date`
    * My Home Directory is $HOME
    TOAST
    

    定界符内转义等同于双引号

    加单引号禁止替换

    cat << 'TOAST'
    * Now : `date`
    * My Home Directory is $HOME
    TOAST
    pwd
    
  • 从命令行获取信息作为标准输入

     <<<word
        base64 <<< meiyoumima
        base64 <<< 'mei you mi ma
    

输出

stdout, fd = 1; stderr, fd = 2

  • > fname 覆盖输出
  • >> fname 追加输出
  • 2> fname 仅 stderr 输出
  • 2>&1 stderr 合并到 stdout 输出
  • 管道
    • ls -l | grep '^d' 前一命令的 stdout 作后一命令的 stdin
    • cc try.c -o try 2>&1 | more 前一命令的 stdout+stderr 作为下一命令的 stdin

开头

#!/bin/bash

表明解释器。

变量

定义

**等号两侧不许多余空格 **

myString="hallo!"
myFiles=`ls -al` # 取执行结果

访问

echo $myString
echo ${addr}

默认:未定义变量,变量值为空字符串

  • set -u 当引用一个未定义的变量时,产生一个错误

  • set +u 当引用一个未定义的变量时,认为是一个空串(默认情形)

  • set -x 执行命令前打印出 shell 替换后的命令及参数, 为区别于正常的 shell 输出, 前面冠以 + 号

  • set +x 取消上述设置

打印

  1. echo
  2. printf
  • printf '\033[01;33mConnect to %s Network\n' $proto

编辑文件

可以使用 ed 命令

printf 'Input IP address of server computer: '
read addr
ed myap.conf > /dev/null 2>&1 << TOAST
/SERVER
.d
i
SERVER $addr
.wq
TOAST
echo Bye

替换

now=date 以命令 date 的 stdout 替换 date

now=$(date) 以命令 date 的 stdout 替换 $(date)

读命令行参数

  • $0 脚本文件本身的名字
  • $1 $2 1 号命令行参数, 2 号命令行参数,以此类推
  • $# 命令行参数的个数
  • $\* 等同于”$1 $2 $3 $4 …”
  • $@ 等同于”$1” ”$2” ”$3”
  • $? 上一命令的返回码

判断返回值是否为 0

if [ $? -ne 0 ]; then
    exit_with_error "Failed to build."
    exit 1
fi

条件

test

/usr/bin/[ 程序:要求其最后一个命令行参数必须为 ]/usr/bin/test 无此要求)

test -r /etc/motd
[ -r /etc/motd ]

文件特性检测

-f 普通文件 -d 目录文件 -r 可读 -w 可写 -x 可执行 -s size>0

test -r /etc/motd && echo readable
[ -r /etc/motd ] && echo readable

字符串比较

["$a&quot; = &quot;&quot;] &amp;&amp; echo empty string 注意:$a 的引号
test $# = 0 && echo "No argument“
level=8
[ $level=0 ] && echo level is Zero

整数的比较

  • -eq

  • -ne

  • -gt

  • -ge

  • -lt

  • -le

例:

 test `ls | wc -l` -ge 100 && echo "Too many files"

逻辑运算

! NOT(非) -o OR (或) -a AND (与)

下面的语句判断参数是否为空:

if [ ! -n "$1" ] ;then
    echo "you have not input a word!"
else
    echo "the word you input is $1"
fi

短路条件

pwd
DIR=/usr/bin
[ -d $DIR ] && (
  cd $DIR
  echo "Current Directory is `pwd`"
  echo "`ls | wc -l` files"
)
pwd

(list) 在子 shell 中执行命令表 list {list;} 在当前 shell 中执行命令表 list

if 分支

if condition
  then list
elif condition
  then list
else
  list
fi

case 分支

case word in
pattern1) list1;;
pattern2) list2;;
...
esac

expr

shell 不支持除字符串以外的数据类型,不支持加减乘除等算数运算和关于字符 串的正则表达式运算

需要这些功能,借助于 shell 之外的可执行程序 /usr/bin/expr 实现

x=`expr $a \\\* \\( $b + $c \)`
y=`expr \( $a + 4 \\&lt; $b \) \& \( $c != 8 \)`
x=`expr $a &#x27;\*&#x27; &#x27;(&#x27; $b + $c ')'`
y=`expr '(' $a + 4 &#x27;&lt;&#x27; $b ')' '&' '(' $c != 8 ')'`

搞颜色

echo -e "\033 [30m 黑色字 \033 [0m"  
echo -e "\033 [31m 红色字 \033 [0m"  
echo -e "\033 [32m 绿色字 \033 [0m"  
echo -e "\033 [33m 黄色字 \033 [0m"  
echo -e "\033 [34m 蓝色字 \033 [0m"  
echo -e "\033 [35m 紫色字 \033 [0m"  
echo -e "\033 [36m 天蓝字 \033 [0m"  
echo -e "\033 [37m 白色字 \033 [0m"  

循环

例:等待文件 lockfile 消失:

while test -r lockfile
do
  sleep 5
done
for i in `seq 1 254`
do
  ping -c 1 -w 1 192.168.0.$i
done

遍历参数

for i
do
  PIDS=`ps -e | awk '/[0-9]:[0-9][0-9] '$i&#x27;$/ { printf("%d ", $1);}'`
  if [ "$PIDs" = "" ]
  then
    echo -e "No \"$i\" is killed."
  else
    echo "kill $PIDS ($i)"
    kill $PIDS
  fi
done

退出

使用 exit RETVAL

exit 0 #正常退出

取扩展名

basename xx.txt .txt
# result is xx

函数

申明

exit_with_error() {
    echo -e "\033 [31m[ERROR]\033 [0m$1"
}

调用

exit_with_error "Failed to build."

参阅

bash 脚本快速入门

Bash bash 中命令行选项 / 参数处理

Extract filename and extension in Bash