Linux Bash 문법 총화

리 눅 스 를 공부 하 는 과정 에서 좋아 하고 골 치 아 픈 신기 한 것 인 bash 프로 그래 밍, 즉 셸 스 크 립 트 를 만 나 는 것 을 피 할 수 없다.그럼 셸 스 크 립 트 는 무엇 일 까요?셸 은 명령 언어 해석 기 이 고 셸 스 크 립 트 는 Linux 명령 의 집합 입 니 다. 미리 설 정 된 순서에 따라 순서대로 해석 하여 실행 하여 특정한 복잡 한 시스템 관리 임 무 를 수행 합 니 다. windows 의 일괄 처리 파일 과 유사 합 니 다.이 박문 은 주로 bash 프로 그래 밍 의 기초 문법 설명 을 소개 한다.
1. bash 프로 그래 밍 의 변수
1) bash 변수 클래스
로 컬 변수: 현재 셸 프로 세 스에 만 유효한 변수 입 니 다. 다른 셸 프로 세 스에 는 유효 하지 않 습 니 다. 현재 셸 프로 세 스 의 하위 프로 세 스 를 포함 합 니 다.
2) 변수 할당:
즉, 변수의 저장 공간 에 데 이 터 를 저장 하 는 것 입 니 다. 다음 과 같 습 니 다.
[root@localhost ~]# VAR_NAME=VALUE

3) 변수의 인용
형식: ${VAR NAME}
" ":弱引用,里面的变量会被替换;
' ':强引用,里面的所有字符都是字面量,直接输出,所见即所得;

4) 환경 변수
현재 셸 프로 세 스 와 하위 셸 에 유효 합 니 다. 다른 셸 프로 세 스 에 유효 하지 않 습 니 다!
定义:VAR_NAME=VALUE
导出:export VAR_NAME
撤销变量:unset VAR_NAME
只读变量:readonly VAR_NAME

5) 부분 변수
셸 스 크 립 트 에서 정의 합 니 다. 셸 스 크 립 트 에서 만 사용 할 수 있 습 니 다!
6) 위치 변수
$1,$2...,${10}

7) 특수 변수
셸 은 일부 매개 변 수 를 특수 처리 합 니 다. 이 매개 변 수 는 인용 만 할 수 있 고 할당 되 지 않 습 니 다!
$#:传递到脚本的参数个数
$*:显示所有向脚本传递的参数                  //与位置变量不同,此选项参数可超过9个
$$:获取当前shell的进程号
$!:执行上一个指令的进程号
$?:获取执行的上一个指令的返回值              //0为执行成功,非零为执行失败
$-:显示shell使用的当前选项,与set命令功能相同
$@  与$*相同,但是使用时加引号,并在引号中返回每个参数

8) 변수 보기
set:查看当前shell进程中的所有变量;
export、printenv、env:查看当前shell进程中的所有环境变量;

9) 변수 이름 규칙
1)不能使用程序中的关键字;
2)只能使用数字、字母和下划线,不可使用数字开头;
3)系统变量默认都是大写,自定义变量尽量不要与系统变量冲突;
4)尽量做到见名知意;

10) 변수 종류
1)数值型:精确数值(整数)、近似数值(浮点数);
2)字符型:char、string;
3)布尔型:true、false;

11) 유형 변환
1)显示转换;
2)隐式转换;

2. bash 설정 파일
기능: 로 컬 변 수 를 설정 하고 명령 별명 을 정의 합 니 다.
1) profile 클래스
profile 클래스: 대화 형 로그 인 사용자 에 게 설정 을 제공 합 니 다!
全局:/etc/profile、/etc/profile.d/*.sh
用户:~/.bash_profile

2) bashrc 류
bashrc 클래스: 비 상호작용 사용자 에 게 설정 을 제공 합 니 다!
全局:/etc/bashrc
用户:~/.bashrc

1) bash 프로 그래 밍 즉 작성 형식 및 실행 방식
1) 서식 작성
셸 스 크 립 트 의 첫 줄 은 반드시 체크 를 해 야 합 니 다. shabang 으로 지정 한 해석 기 를 정의 하여 이 스 크 립 트 를 해석 해 야 합 니 다.
#!/bin/bash       //!即为shebang
//其它的以#开头的行均为注释,会被解释器忽略,可用来注释脚本用途及版本,方便使用管理。

2) 실행 방식
bash 프로 그래 밍 은 프로 세 스 프로 그래 밍 에 속 합 니 다. 실행 방식 은 다음 과 같 습 니 다.
1)顺序执行:按命令先后顺寻依次执行;
2)选择执行:测试条件,可能会多个测试条件,某条件满足时,则执行对应的分支;
3)循环执行:将同一段代码反复执行多次,因此,循环必须有退出条件;否则,则陷入死循环;

3) bash 실행 옵션
1)bash -n SHELLNAME  #语法测试,测试是否存在语法错误;
2)bash -x SHELLNAME  #模拟单步执行,显示每一步执行过程;

2) bash 의 산수 연산 과 논리 연산
1) 산수 연산
정형 변수 정의:
1)et VAR_NAME=INTEGER_VALUE            //例如:let a=3
2)declare -i VAR_NAME=INTEGER_VALUE     //例如:declare -i a=3

산술 연산 을 실현 하 는 방식:
let VAR_NAME=ARITHMATIC_EXPRESSION
VAR_NAME=$[ARITHMATIC_EXRESSION]
VAR_NAME=$((EXPRESSION))
VAR_NAME=$(expr $num1 + $num2)

알고리즘 연산 자:
+:加法
-:减法
*:乘法
/:整除
%:取余数
**:乘幂

메모: 정형 변수 로 정의 되 지 않 아 도 문자 형의 숫자 는 산술 연산 에 참여 할 수 있 습 니 다. bash 는 변수 형식의 암시 적 형식 변환 을 수행 합 니 다.
2) 논리 연산
布尔运算:真,假
与运算:真 && 真 = 真
        真 && 假 = 假
        假 && 真 = 假
        假 && 假 = 假
或运算:真 || 真 = 真
  真 || 假 = 真
  假 || 真 = 真
  假 || 假 = 假
非运算:!真=假
        !假=真

3) bash 프로 그래 밍 의 조건 시험 문
1) bash 조건 부 테스트
정형 테스트: 정수 비교
例如 [ $num1 -gt $num2 ]

-gt: 大于
-lt: 小于
-ge: 大于等于
-le: 小于等于
-eq: 等于
-ne: 不等于

문자 테스트: 문자열 비교
双目:
例如[[ "$str1" > "$str2" ]]

>: 大于则为真
<:>=:大于等于则为真
<=:小于等于则为真
==:等于则为真
!=:不等于则为真

单目:
-n String: 是否不空,不空则为真,空则为假
-z String: 是否为空,空则为真,不空则假

文件测试:判断文件的存在性及属性等

-a FILE:存在则为真;否则则为假;
-e FILE:存在则为真;否则则为假;
-f FILE: 存在并且为普通文件,则为真;否则为假;
-d FILE: 存在并且为目录文件,则为真;否则为假;
-L/-h FILE: 存在并且为符号链接文件,则为真;否则为假;
-b: 存在并且为块设备,则为真;否则为假;
-c: 存在并且为字符设备,则为真;否则为假
-S: 存在并且为套接字文件,则为真;否则为假
-p: 存在并且为命名管道,则为真;否则为假
-s FILE: 存在并且为非空文件则为值,否则为假;
-r FILE:文件可读为真,否则为假
-w FILE:文件可写为真,否则为假
-x FILE:文件可执行为真,否则为假
file1 -nt file2: file1的mtime新于file2则为真,否则为假;
file1 -ot file2:file1的mtime旧于file2则为真,否则为假;

组合条件测试:在多个条件间实现逻辑运算

与:[ condition1 -a condition2 ]
  condition1 && condition2
或:[ condition1 -o condition2 ]
  condition1 || condition2
非:[ -not condition ]
  ! condition
与:COMMAND1 && COMMAND2
COMMAND1如果为假,则COMMAND2不执行
或:COMMAND1 || COMMAND2
COMMAND1如果为真,则COMMAND2不执行
非:! COMMAND

2) 조건 부 테스트 의 if 문장
1、if语句之单分支
语句结构:
if 测试条件;then
   选择分支
fi
表示条件测试状态返回值为值,则执行选择分支
例:写一个脚本,接受一个参数,这个参数是用户名;如果此用户不存在,则创建该用户;

#!/bin/bash
if ! id $1 &> /dev/null;then
  useradd $1
fi

2、if语句之双分支
语句结构:
if 测试条件;then
   选择分支1
else
   选择分支2
fi

两个分支仅执行其中之一
例:通过命令行给定一个文件路径,而后判断:如果此文件中存在空白行,则显示其空白行的总数;否则,则显示无空白行;
#!/bin/bash
if grep "^[[:space]]*$" $1 &> /dev/null; then
  echo "$1 has $(grep "^[[:space]]*$" $1 | wc -l) blank lines."
else
  echo "No blank lines"
fi

注意:如果把命令执行成功与否当作条件,则if语句后必须只跟命令本身,而不能引用。

3、if语句之多分支
语句结构:
if 条件1;then
     分支1
elif 条件2;then
     分支2
elif 条件3;then
     分支3
      ...
else
     分支n
fi

例:传递一个用户名给脚本:如果此用户的id号为0,则显示说这是管理员;如果此用户的id号大于等于500,则显示说这是普通用户;否则,则说这是系统用户。
#!/bin/bash
if [ $# -lt 1 ]; then
  echo "Usage: `basename $0` username"
  exit 1
fi
if ! id -u $1 &> /dev/null; then
  echo "Usage: `basename $0` username"
  echo "No this user $1."
  exit 2
fi

if [ $(id -u $1) -eq 0 ]; then
  echo "Admin"
elif [ $(id -u $1) -ge 500 ]; then
  echo "Common user."
else
  echo "System user."
fi

3) bash 대화 형 프로 그래 밍
read [option] “prompt”-p:直接指定一个变量接受参数
-t timaout:指定等待接受参数的时间
-n:表示不换行

例:输入用户名,可返回其shell

#!/bin/bash
read -p "Plz input a username: " userName
if id $userName &> /dev/null; then
    echo "The shell of $userName is `grep "^$userName\>" /etc/passwd | cut -d: -f7`."
else
    echo "No such user. stupid."
fi  

4) 조건 부 테스트 와 case 문장
case语句:有多个测试条件时,case语句会使得语法结构更明晰
语句结构:

case 变量引用 in
PATTERN1)
  分支1
;;
PATTERN2)
  分支2
;;
...
*)
  分支n
;;
esac

PATTERN: 파일 이름 연결 메커니즘 과 유사 하지만 사용 | 표시 또는
 a|b:  a或者b*:匹配任意长度的任意字符
?: 匹配任意单个字符
[]: 指定范围内的任意单个字符

例:写一个脚本,完成如下任务,其使用形式如下所示:
script.sh {start|stop|restart|status}

其中:如果参数为空,则显示帮助信息,并退出脚本;
如果参数为start,则创建空文件/var/lock/subsys/script,并显示“starting script successfully.”
如果参数为stop,则删除文件/var/lock/subsys/script,并显示“Stop script successfully.”
如果参数为restart,则删除文件/var/locksubsys/script并重新创建,而后显示“Restarting script successfully.”
如果参数为status,那么:如果文件/var/lock/subsys/script存在,则显示“Script is running…”,否则,则显示“Script is stopped.”

#!/bin/bash
file='/var/lock/subsys/script'
case $1 in
start)
  if [ -f $file ];then
  echo "Script is running..."
    exit 3
  else
  touch $file
  [ $? -eq 0 ] && echo "Starting script successfully."
  fi
  ;;
stop)
  if [ -f $file ];then
  rm -rf $file
  [ $? -eq 0 ] && echo "Stop script successfully."
  else
  echo "Script is stopped..."
  exit 4
  fi
  ;;
restart)
  if [ -f $file ];then
  rm -rf $file
  [ $? -eq 0 ] && echo "Stop script successfully"
  else 
  echo "Script is stopped..."
  exit 5
  fi
  touch $file
  [ $? -eq 0 ] && echo "Starting script successfully"
  ;;
status)
  if [ -f $file ];then
  echo "Script is running..."
  else
  echo "Script is stopped."
  fi
  ;;
*)
  echo "`basename $0` {start|stop|restart|status}"
  exit 2
  ;;
 esac

4) bash 프로 그래 밍 의 순환 문
1) 순환 의 for 순환
1、for语句格式一
语句结构:
for 变量名 in 列表; do
    循环体
done
列表:可包含一个或多个元素
循环体:依赖于调用变量来实现其变化
循环可嵌套
退出条件:遍历元素列表结束
例:求100以内所有正整数之和

#!/bin/bash
declare -i sum=0
for i in {1..100}; do
    let sum+=$i
done
echo $sum

2、for语句格式二
for ((初始条件;测试条件;修改表达式)); do
      循环体
done
先用初始条件和测试条件做判断,如果符合测试条件则执行循环体,再修改表达式,否则直接跳出循环。

例:求100以内所有正整数之和(for二实现)
#!/bin/bash
declare -i sum=0
for ((counter=1;$counter <= 100; counter++)); do
  let sum+=$counter
done
echo $sum

2) 순환 하 는 while 문장
while 순환 문 구 는 순환 횟수 가 알 수 없 거나 for 에 적용 되 지 않 아 큰 목록 을 직접 생 성 합 니 다!
语句结构:
while 测试条件; do
  循环体
done
测试条件为真,进入循环;测试条件为假,退出循环
例1:求100以内所有偶数之和,要求使用取模方法
#!/bin/bash
declare -i counter=1
declare -i sum=0
while [ $counter -le 100 ]; do
  if [ $[$counter%2] -eq 0 ]; then
     let sum+=$counter
  fi
  let counter++
 done
echo $sum

例2:提示用户输入一个用户名,如果用户存在,就显示用户的ID号和shell;否则显示用户不存在;显示完成之后不退出,再次重复前面的操作,直到用户输入q或quit为止
#!/bin/bash
read -p "Plz enter a username: " userName
while [ "$userName" != 'q' -a "$userName" != 'quit' ]; do
  if id $userName &> /dev/null; then
     grep "^$userName\>" /etc/passwd | cut -d: -f3,7
  else
    echo "No such user."
  fi
read -p "Plz enter a username again: " userName
done

while特殊用法:遍历文本文件
语句结构:
while read 变量名; do
  循环体
done < /path/to/somefile
变量名,每循环一次,记忆了文件中一行文本

例:显示ID号为偶数,且ID号同GID的用户的用户名、ID和SHELL
while read line; do
  userID=`echo $line | cut -d: -f3`
  groupID=`echo $line | cut -d: -f4`
  if [ $[$userID%2] -eq 0 -a $userID -eq $groupID ]; then
     echo $line | cut -d: -f1,3,7
  fi
done < /etc/passwd

3) 순환 의 until 문장
语句结构:
until 测试条件; do
      循环体
done
测试条件为假,进入循环;测试条件为真,退出循环

例:求100以内所有偶数之和,要求使用取模方法(until实现)

#!/bin/bash
declare -i counter=1
declare -i sum=0
until [ $counter -gt 100 ]; do
  if [ $[$counter%2] -eq 0 ]; then
     let sum+=$counter
  fi
  let counter++
done
echo $sum
例:提示用户输入一个用户名,如果用户存在,就显示用户的ID号和shell;否则显示用户不存在;显示完成之后不退出,再次重复前面的操作,直到用户输入q或quit为止(until实现)

#!/bin/bash
read -p "Plz enter a username: " userName
until [ "$userName" = 'q' -a "$userName" = 'quit' ]; do
  if id $userName &> /dev/null; then
   grep "^$userName\>" /etc/passwd | cut -d: -f3,7
else
echo "No such user."
fi
read -p "Plz enter a username again: " userName
done

4) 순환 제어 와 shift
循环控制命令:
1)break:提前退出循环;
2)break [N]: 退出N层循环;N省略时表示退出break语句所在的循环;
3)continue: 提前结束本轮循环,而直接进入下轮循环;
4)continue [N]:提前第N层的循环的本轮循环,而直接进入下轮循环;

5) 사순환
#while体while true; do
      循环体
done
#until体
until false; do
      循环体
done

例1:写一个脚本,判断给定的用户是否登录了当前系统
(1) 如果登录了,则脚本终止;
(2) 每5秒种,查看一次用户是否登录;
#!/bin/bash
while true; do
    who | grep "gentoo" &> /dev/null
    if [ $? -eq 0 ];then
break
    fi
    sleep 5
done
echo "gentoo is logged."

6)shift
위치 매개 변 수 는 shift 명령 으로 왼쪽으로 이동 할 수 있 습 니 다. 예 를 들 어 shift 3 은 원래 의 $4 가 현재 $1 이 되 고 원래 의 $5 가 $2 가 되 는 등 원래 의 $1, $2, $3 을 버 리 고 $0 은 이동 하지 않 습 니 다.인자 가 없 는 shift 명령 은 shift 1 에 해당 합 니 다.
위치 변수 나 명령 행 인자 에 대해 서 는 개수 가 확실 해 야 하거나 셸 프로그램 이 개 수 를 모 를 때 모든 인 자 를 '$*' 로 복사 할 수 있다 는 것 을 알 고 있 습 니 다.사용자 가 Shell 에 게 위치 변수 개 수 를 모 르 는 상황 에서 매개 변 수 를 하나씩 처리 하 라 고 요구 하면 $1 이후 에 $2 이 고 $2 뒤에 $3 등 입 니 다.shift 명령 이 실행 되 기 전 변수 $1 의 값 은 shift 명령 이 실 행 된 후 사용 할 수 없습니다.
실례 는 다음 과 같다.
[root@localhost ~]# cat 1.sh
#!/bin/bash
while [ $# -ne 0 ]
do
echo "第一个参数为:$1  参数个数为:$#"
shift
done
[root@localhost ~]# sh 1.sh 1 2 3 4
第一个参数为:1  参数个数为:4
第一个参数为:2  参数个数为:3
第一个参数为:3  参数个数为:2
第一个参数为:4  参数个数为:1

위의 예 에서 shift 명령 이 실 행 될 때마다 변수의 개수 ($\#) 는 1 을 줄 이 고 변수의 값 은 한 자 리 를 앞 당 기 는 것 을 알 수 있 습 니 다.
실례 2 는 다음 과 같다.
[root@localhost ~]# cat 2.sh
#!/bin/bash
if [ $# -eq 0 ]
then
echo "Usage:2.sh 参数"
exit 1
fi
sum=0
while [ $# -ne 0 ]
do
sum=`expr ${sum} + $1`
shift
done
echo "sum is:${sum}"
[root@localhost ~]# sh 2.sh 10 20 30
sum is:60

shift 명령 은 또 하나의 중요 한 용도 가 있 습 니 다. Bash 는 9 개의 위치 변 수 를 정의 합 니 다. $1 에서 $9 까지 사용자 가 명령 행 에서 9 개의 매개 변 수 를 사용 할 수 있 는 것 은 아 닙 니 다. shift 명령 을 통 해 9 개 이상 의 매개 변 수 를 방문 할 수 있 습 니 다.
shift 명령 이 매개 변수 로 한 번 이동 하 는 개 수 는 셸 프로그램 이 9 개의 명령 행 인 자 를 처리 한 후 shift 9 명령 으로 $10 을 $1 로 이동 할 수 있 습 니 다.
5) bash 프로 그래 밍 함수
문법 구조:
function F_NAME {    
   函数体
  }
或
  F_NAME() {
    函数体
  }
可调用:使用函数名,函数名出现的地方,会被自动替换为函数;
函数的返回值:
函数的执行结果返回值:代码的输出
函数中使用打印语句:echo, printf
函数中调用的系统命令执行后返回的结果
执行状态返回值:
默认取决于函数体执行的最后一个命令状态结果
自定义退出状态码:return [0-255]

메모: 함수 체 가 실 행 될 때 return 문 구 를 만나면 함수 가 되 돌아 갑 니 다!
1) 함 수 는 매개 변 수 를 수신 할 수 있다.
함수 에서 함수 인 자 를 호출 하 는 방식 은 스 크 립 트 에서 스 크 립 트 인 자 를 호출 하 는 방식 과 같 습 니 다.
位置参数
$1, $2, …
$#, $*, $@

인 스 턴 스: 다음 과 같이 요구 합 니 다. 1) 사용자 에 게 실행 가능 한 명령 을 입력 하 라 고 알려 줍 니 다.2) 이 명령 에 의존 하 는 모든 라 이브 러 리 파일 가 져 오기 (ldd 명령 사용);3) 명령 의/mnt/sysroot 디 렉 터 리 복사 하기;4) 각 라 이브 러 리 파일 을/mnt/sysroot 에 대응 하 는 디 렉 터 리 로 복사 합 니 다.
[root@localhost ~]# cat 1.sh
#!/bin/bash
target=/mnt/sysroot/
[ -d $target ] || mkdir $target
preCommand() {
    if which $1 &> /dev/null; then
  commandPath=`which --skip-alias $1`
  return 0
    else
  echo "No such command."
  return 1
    fi
}

commandCopy() {
    commandDir=`dirname $1`
    [ -d ${target}${commandDir} ] || mkdir -p ${target}${commandDir}
    [ -f ${target}${commandPath} ] || cp $1 ${target}${commandDir}
}

libCopy() {
    for lib in `ldd $1 | egrep -o "/[^[:space:]]+"`; do
libDir=`dirname $lib`
[ -d ${target}${libDir} ] || mkdir -p ${target}${libDir}
[ -f ${target}${lib} ] || cp $lib ${target}${libDir}
    done
} 
read -p "Plz enter a command: " command

until [ "$command" == 'quit' ]; do

  if preCommand $command &> /dev/null; then
    commandCopy $commandPath
    libCopy $commandPath
  fi
    exit 1
done
[root@localhost ~]# sh 1.sh
Plz enter a command: cat
[root@localhost ~]# ls /mnt/sysroot/bin/
cat
[root@localhost ~]# ls /mnt/sysroot/
bin  lib64

2) bash 프로 그래 밍 의 신호 포착
trap 명령 은 셸 프로그램 에서 신 호 를 포착 한 후에 세 가지 반응 방식 으로 사용 할 수 있 습 니 다. 1) 프로그램 을 실행 하여 이 신 호 를 처리 할 수 있 습 니 다.2) 신 호 를 받 는 기본 동작;3) 이 신 호 를 무시 합 니 다.
예제: 네트워크 에 있 는 모든 호스트 가 온라인 인지 확인 할 수 있 는 스 크 립 트 를 작성 합 니 다. 실행 이 끝나 지 않 았 을 때 ctrl + c 명령 을 받 고 종료 할 수 있 습 니 다.
[root@localhost ~]# cat 1.sh
#!/bin/bash
quitScript() {
   echo "Quit..."
}    
trap 'quitScript; exit 5' SIGINT

cnetPing() {
  for i in {1..254}; do
    if ping -c 1 -W 1 $1.$i &> /dev/null; then
      echo "$1.$i is up."
     else
      echo "$1.$i is down."
    fi
    done
}

bnetPing() {
  for j in {0..255}; do
    cnetPing $1.$j 
  done
}
anetPing() {
for m in {0..255}; do
bnetPing $1.$m
done
}

netType=`echo $1 | cut -d"." -f1`

if [ $netType -ge 1 -a $netType -le 126 ]; then
anetPing $netType
elif [ $netType -ge 128 -a $netType -le 191 ]; then
bnetPing $(echo $1 | cut -d'.' -f1,2)
elif [ $netType -ge 192 -a $netType -le 223 ]; then
cnetPing $(echo $1 | cut -d'.' -f1-3)
else
echo "Wrong"
exit 2
fi
[root@localhost ~]# sh 1.sh 192.168.1.1
192.168.1.1 is down.
192.168.1.2 is down.
192.168.1.3 is down.
192.168.1.4 is down.
192.168.1.5 is down.
192.168.1.6 is down.
192.168.1.7 is down.
192.168.1.8 is down.
192.168.1.9 is down.
192.168.1.10 is up.
192.168.1.11 is down.
^CQuit...

- - - 이번 박문 은 여기 서 끝 났 습 니 다. 읽 어 주 셔 서 감사합니다. - -

좋은 웹페이지 즐겨찾기