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 -
使用定界符:
1cat << TOAST 2* Now : `date` 3* My Home Directory is $HOME 4TOAST
定界符内转义等同于双引号
加单引号禁止替换
1cat << 'TOAST' 2* Now : `date` 3* My Home Directory is $HOME 4TOAST 5pwd
-
从命令行获取信息作为标准输入
1 <<<word 2 base64 <<< meiyoumima 3 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
-
开头
1#!/bin/bash
表明解释器。
变量
定义
注意 等号两侧不许多余空格
1myString="hallo!"
2myFiles=`ls -al` # 取执行结果
访问
1echo $myString
2echo ${addr}
默认:未定义变量,变量值为空字符串
-
set -u
当引用一个未定义的变量时,产生一个错误 -
set +u
当引用一个未定义的变量时,认为是一个空串(默认情形) -
set -x
执行命令前打印出shell替换后的命令及参数, 为区别于正常的 shell输出, 前面冠以+号 -
set +x
取消上述设置
打印
-
echo
-
printf
printf '\033[01;33mConnect to %s Network\n' $proto
编辑文件
可以使用 ed
命令
1printf 'Input IP address of server computer: '
2read addr
3ed myap.conf > /dev/null 2>&1 << TOAST
4/SERVER
5.d
6i
7SERVER $addr
8.wq
9TOAST
10echo Bye
替换
now=date
以命令date 的stdout替换date
now=$(date) 以命令date 的stdout替换$(date)
读命令行参数
-
$0
脚本文件本身的名字 -
$1
$2
1号命令行参数, 2号命令行参数,以此类推 -
$#
命令行参数的个数 -
$*
等同于”$1 $2 $3 $4 …” -
$@
等同于”$1” ”$2” ”$3” -
$?
上一命令的返回码
判断返回值是否为 0
1if [ $? -ne 0 ]; then
2 exit_with_error "Failed to build."
3 exit 1
4fi
条件
test
/usr/bin/[
程序:要求其最后一个命令行参数必须为 ]
(/usr/bin/test
无此要求)
1test -r /etc/motd
2[ -r /etc/motd ]
文件特性检测
-f
普通文件 -d
目录文件 -r
可读 -w
可写 -x
可执行 -s
size>0
1test -r /etc/motd && echo readable
2[ -r /etc/motd ] && echo readable
字符串比较
1[ "$a" = "" ] && echo empty string 注意:$a的引号
2test $# = 0 && echo "No argument“
3level=8
4[ $level=0 ] && echo level is Zero
整数的比较
-
-eq
= -
-ne
≠ -
-gt
> -
-ge
≥ -
-lt
< -
-le
≤
例:
1 test `ls | wc -l` -ge 100 && echo "Too many files"
逻辑运算
! NOT(非) -o OR (或) -a AND (与)
下面的语句判断参数是否为空:
1if [ ! -n "$1" ] ;then
2 echo "you have not input a word!"
3else
4 echo "the word you input is $1"
5fi
短路条件
1pwd
2DIR=/usr/bin
3[ -d $DIR ] && (
4 cd $DIR
5 echo "Current Directory is `pwd`"
6 echo "`ls | wc -l` files"
7)
8pwd
(list)
在子shell中执行命令表list { list;}
在当前shell中执行命令表list
if 分支
1if condition
2 then list
3elif condition
4 then list
5else
6 list
7fi
case 分支
1case word in
2pattern1) list1;;
3pattern2) list2;;
4...
5esac
expr
shell不支持除字符串以外的数据类型,不支持加减乘除等算数运算和关于字符 串的正则表达式运算
需要这些功能,借助于shell之外的可执行程序/usr/bin/expr实现
1x=`expr $a \* \( $b + $c \)`
2y=`expr \( $a + 4 \< $b \) \& \( $c != 8 \)`
3x=`expr $a '*' '(' $b + $c ')'`
4y=`expr '(' $a + 4 '<' $b ')' '&' '(' $c != 8 ')'`
搞颜色
1echo -e "\033[30m黑色字\033[0m"
2echo -e "\033[31m红色字\033[0m"
3echo -e "\033[32m绿色字\033[0m"
4echo -e "\033[33m黄色字\033[0m"
5echo -e "\033[34m蓝色字\033[0m"
6echo -e "\033[35m紫色字\033[0m"
7echo -e "\033[36m天蓝字\033[0m"
8echo -e "\033[37m白色字\033[0m"
循环
例:等待文件lockfile消失:
1while test -r lockfile
2do
3 sleep 5
4done
1for i in `seq 1 254`
2do
3 ping -c 1 -w 1 192.168.0.$i
4done
遍历参数
1for i
2do
3 PIDS=`ps -e | awk '/[0-9]:[0-9][0-9] '$i'$/ { printf("%d ", $1);}'`
4 if [ "$PIDs" = "" ]
5 then
6 echo -e "No \"$i\" is killed."
7 else
8 echo "kill $PIDS ($i)"
9 kill $PIDS
10 fi
11done
退出
使用 exit RETVAL
1exit 0 #正常退出
取扩展名
1basename xx.txt .txt
2# result is xx
函数
申明
1exit_with_error() {
2 echo -e "\033 [31m[ERROR]\033 [0m$1"
3}
调用
1exit_with_error "Failed to build."
特殊变量
变量 | 含义 |
---|---|
$0 | 当前脚本的文件名 |
$n | 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2。 |
$# | 传递给脚本或函数的参数个数。 |
$* | 传递给脚本或函数的所有参数:"$1", "$2", “$3”, 每个变量是独立的。 |
$@ | 传递给脚本或函数的所有参数:"$1 $2 $3",代表 |
$? | 上个命令的退出状态,或函数的返回值。 |
? | 当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。 |
参数扩展
“扩展”可以理解为 C 对指针的解引用。
例如:
1myvar1=hello
2myvar2=myvar1
3
4echo hello # 输出 hello
5echo myvar1 # 输出 myvar1
6echo $myvar1 # 输出 hello
7echo myvar2 # 输出 myvar2
8echo $myvar2 # 输出 myvar1
9echo ${!myvar2} # 输出 hello
10
11myvar3=myvar2
12echo ${!myvar3} # 输出 myvar1
$
是进行一次扩展。
${!ID}
是进行两次扩展。
判断参数是否为空:
1a=${b-c}
2echo $a # 输出 c
3echo $b # 输出
4echo $c # 输出
1b=whatever
2a=${b:c}
3echo $a # 输出 whatever
加上等号,可以判断不存在且不为空值(即 b=
)