# Shell学习

## 1. 变量名

变量名外面的花括号是可选的，加不加都行，加花括号是为了帮助解释器识别变量的边界。

推荐给所有变量加上花括号，这是个好的编程习惯。

## 2. 单引号双引号

单引号里的任何字符都会原样输出，单引号字符串中的变量是无效的；单引号字串中不能出现单引号（对单引号使用转义符后也不行）。双引号里可以有变量，双引号里可以出现转义字符。

```
>  echo "${JAVA_HOME}"
/home/wangjun/jdk1.8.0_181
>  echo '${JAVA_HOME}'
${JAVA_HOME}
```

## 3. expr命令

expr 是一款表达式计算工具，使用它能完成表达式的求值操作。

例如，两个数相加(注意使用的是反引号 \` 而不是单引号 ')

```
#!/bin/bash
val=`expr 2 + 2`
echo "两数之和为 : $val"
```

## 4. 位置变量

位置变量指的是函数或脚本后跟的第 n 个参数。 需要注意的是从第 10 个开始要用花括号调用，例如${10} 。

shift 可对位置变量控制，每执行一次 shift 命令，位置变量个数就会减一，而变量值则提前一位。shift n，可设置向前移动

n 位。例如：

```
#!/bin/bash

echo "1: $1"

shift

echo "2: $2"

shift

echo "3: $3"

# bash test.sh a b c

1: a

2: c

3:
```

特殊变量：

| 符号  | 描述                                                   |
| --- | ---------------------------------------------------- |
| $0  | 脚本自身名字                                               |
| $?  | 返回上一条命令是否执行成功，0 为执行成功，非 0 则为执行失败，存放上一次进程的结束状态（退出状态码） |
| $#  | 位置参数总数                                               |
| $\* | 所有的：位置参数被看做一个字符串                                     |
| $@  | 每个位置参数被看做独立的字符串                                      |
| $$  | 当前进程 PID                                             |
| $!  | 上一条运行后台进程的 PID                                       |

## 5. 判断条件

**数值：**

| 运算符 | 描述   |
| --- | ---- |
| -eq | 等于   |
| -ne | 不等于  |
| -gt | 大于   |
| -lt | 小于   |
| -ge | 大于等于 |
| -le | 小于等于 |

**字符串：**

| 运算符 | 描述     |
| --- | ------ |
| -n  | 字符串不为空 |
| -z  | 字符串为空  |

**文件：**

| 符号 | 描述    |
| -- | ----- |
| -f | 是文件   |
| -d | 是文件夹  |
| -s | 文件有内容 |
| -x | 文件可执行 |
| -e | 文件存在  |

**通用：**

| 符号 | 描述  |
| -- | --- |
| -a | 逻辑与 |
| -o | 逻辑或 |

在bash中，test命令可以使用\[]运算符取代，但需要注意 \[ 之后和 ] 之前需要加空格。eg：判断输入的第一个参数不为空

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

# 也可以使用test
#!/bin/bash
if test -z $1; then
    echo "you have not input a word!"
else
    echo "the word you input is $1"
fi
```

## 6. 循环

```
# for语句格式
for 变量名 in 取值列表; do
    命令
done

# 比如
#!/bin/bash
for i in {1..3}; do
    echo $i
done
# 也可以这样
#!/bin/bash
for ((i=1; i<=3; i++)); do 
    echo $i
done

# 遍历当前文件夹
#!/bin/sh
for file in ./*
do
        if test -d $file
        then
                cd $file
                git pull
                echo "$file pull finished!"
                cd ..
        fi
done

# while语句格式
while 条件表达式; do
命令
done

# 比如
#!/bin/bash
N=0
while [ $N -lt 5 ]; do
    let N++
    echo $N
done

# 逐行读取文本
# 方式 1：
#!/bin/bash
cat ./a.txt | while read LINE; do
    echo $LINE
done

# 方式 2：
#!/bin/bash
while read LINE; do
    echo $LINE
done < ./a.txt

# 方式 3：
#!/bin/bash
exec < ./a.txt # 读取文件作为标准输出
while read LINE; do
    echo $LINE
done
```

## shell实战实例

从另一个文件中拷贝100份并 替换指定字符

```
#!/bin/sh
for i in {0..99}; do
        while read line || [[ -n $line ]]; do # [[ ]]解决读取不到文件的最后一行
                POSTFIX="_$i"
                LINE=${line/_0/$POSTFIX} # 将_0替换成_i
                echo $LINE >> ./chat_msg_open.sql
        done < ./chat_msg.sql
        echo -e "\n" >> ./chat_msg_open.sql # -e 使echo支持转移符--换行
done
```
