# Bash基础入门与应用

#### Shell执行方式

```bash
bash hello.sh #方式一
cat hello.sh | bash #方式二
bash < hello.sh #方式三
chmod +x hello.sh #方式四
 
#方式五
source hello.sh
#source有一个简写形式，可以使用一个点（.）来表示。
 
#方式六，远程加载执行
curl -s http://localhost/hello.sh |bash
 
#wget方式
wget -qO - http://localhost/hello.sh|bash
```

#### 配置文件

全局，针对所有用户

```bash
/etc/profile
/etc/profile.d/*.sh
/etc/bashrc
 
#只针对个人
~/.bash_profile
~/.bashrc
```

#### 环境变量

常用环境变量

```bash
#显示所有变量以及BASH函数
set
```

BASHPID：Bash 进程的进程 ID。

DISPLAY：图形环境的显示器名字，通常是:0，表示 X Server 的第一个显示器。

IFS：词与词之间的分隔符，默认为空格。

LANG：字符集以及语言编码，比如zh\_CN.UTF-8。

PATH：由冒号分开的目录列表，当输入可执行程序名后，会搜索这个目录列表。

SHELL：Shell 的名字。

SHELLOPTS：启动当前 Shell 的set命令的参数，参见《set 命令》一章。

TERM：终端类型名，即终端仿真器所用的协议。

内置变量：PS1，PATH，UID，HOSTNAME，$$，BASHPID，PPID，$?，HISTSIZE

#### 位置、特殊变量

$1，$2 #对应参数

$0 #命令本身

$\*  #全部参数命为一个字符串

$@ #每个参数为独立字符串

$# #传递给脚本的参数的个数

$? #0代表成功

$? 值   1-255 #代表失败

$$ #当前SHell的进程ID

$\_ #为上一个命令的最后一个参数

$! #为最后一个后台执行的异步命令的进程ID

$- #当前Shell启动参数

$? 是一个特殊变量，用来获取上一个命令的退出状态，或者上一个函数的返回值。

&#x20;

用户自定义变量

```bash
#直接字串
name='root'
 
#变量引用
name="$USER"
 
#命令引用
name=`COMMAND` 或 name=$(COMMAND)
```

变量引用

· $name

弱引用，变量引用会被替换为变量值

· ${name}

强引用，不会替换为变量值，保持原字符

&#x20;

如果变量的值本身也是变量，使用${!varname}读取最终的值

```bash
#环境变量，可用变量传递给子Shll
export name=VALUE
declare -x name=VALUE
 
#删除变量
unset NAME
 
#只读变量，常量
readonly [-p]
declare -r
```

#### 脚本调试

```bash
#只检测语法错误
bash -n hello.sh
 
#调试并执行
bash -x hello.sh
```

#### 字符串操作

```bash
#获取字符串长度
${#varname}
 
#子字符串
${varname:offset:length}
 
#搜索和替换
myccav=/home/ccav/book/administrator.ini
##最短匹配
echo ${myccav#/*/}
ccav/book/administrator.ini
 
##最长匹配
echo ${myccav##/*/}
administrator.ini
 
##只留文件名
echo  ${myccav##*/}
 
#替换，将administrator替换为root，加//替换所有
echo  ${myccav/administrator/root}
 
#转换大写
${varname^^}
 
#转换小写
${varname,,}
```

&#x20;

#### 判断

注意 \[ ] 需要空格，否则会报错误

\[ ]和\[ \[ ] ]的区别是，双括号是增加版，支持正则表达式和通配符

{% code overflow="wrap" %}

```bash
#判断后缀
[[ "$FILE" == *.log ]]
 
#判断合法非负整数
[[ "$N" =~  ^[0-9]+$  ]]
 
#判断合法IP
[[ "$IP" =~  ^([0-9]{1,3}\.){3}[0-9]{1,3}$  ]]
[[ $IP =~ ^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]]
```

{% endcode %}

```bash
-eq 是否等于
-ne 是否不等于
-gt 是否大于
-ge 是否大于等于
-lt 是否小于
-le 是否小于等于
 
-z 字符串是否为空
-n 字符串是否不为空

#判断文件
-a FILE:同 -e
-e FILE: 文件存在性测试，存在为真，否则为假
-b FILE:是否存在且为块设备文件
-c FILE:是否存在且为字符设备文件
-d FILE:是否存在且为目录文件
-f FILE:是否存在且为普通文件
-h FILE 或 -L FILE:存在且为符号链接文件
-p FILE:是否存在且为命名管道文件
-S FILE:是否存在且为套接字文件
 
#文件权限
-r FILE:是否存在且可读
-w FILE: 是否存在且可写
-x FILE: 是否存在且可执行
-u FILE:是否存在且拥有suid权限
-g FILE:是否存在且拥有sgid权限
-k FILE:是否存在且拥有sticky权限
```

&#x20;

#### read

-p 指定要显示的提示

-s 静默输入，一般用于密码

-n N 指定输入的字符长度N

-d '字符' -t N 输入结束符 TIMEOUT为N秒

```bash
#输入
read -p "Input Password：" PASSWORD
echo $PASSWORD
 
#判断输入Yes
read -p "Yes or No:" ANSWER
[[ $ANSWER =~ ^([Yy]|[Yy][Ee][Ss])$ ]] && echo "Yes" || echo "No"
 
answer=`echo $input| tr 'A-Z' 'a-z'`
[ $answer = 'yes' -o $answer = 'y' ] && echo YES
[ $answer = 'no' -o $answer = 'n' ] && echo NO
```

#### 流程控制

```bash
#单分支
if 判断条件;then 条件为真的分支代码
fi
 
#双分支
if 判断条件; then 条件为真的分支代码
else
条件为假的分支代码
fi
 
#多分支
if 判断条件1; then 条件1为真的分支代码
elif 判断条件2; then 条件2为真的分支代码
elif 判断条件3; then 条件3为真的分支代码
...
else
  以上条件都为假的分支代码
fi
```

#### 条件判断case语句

```bash
case 变量引用 in PAT1)
分支1
;; PAT2)
分支2
;; ...
*)
;;
esac
 
例子：
case $INPUT in
[yY]|[Yy][Ee][Ss])
echo "Yes"
  ;;
[Nn]|[Nn][Oo])
echo "No"
  ;;
*)
;;
easc

#case多分支
case $option in
1)
select parameter in "a" "b";do
  case $parameter in
  a)
  echo "aaaa"
  break
  ;;
  b)
  echo "bbbb"
  break
  ;;
  easc
2)
...
easc
nmap扫描脚本
nmap 127.0.0.0.1
nmap -sV -Pn 127.0.0.1 -v -n
 
read -p "Input Target：" target
case options in
  1)
  nmap -sV -Pn $target -v -n
  ;;
  2)
  nmap -sV -Pn -p 1-1024,7000-9000 $target -v -n
  ;;
  3)
  nmap -sV -Pn -p1-65535 $target -v -n
  ;;
  4)
  nmap -O -Pn $target
  ;;
esac
```

#### 循环

```bash
#方式1
for 变量名 in 列表;do
循环体
done
 
#方式2
for 变量名 in 列表
do
循环体
done
 
#批量创建用户并设置密码
for i in {1..10};do
useradd user$i
  PASS=`cat /dev/urandom|tr -dc '[:alnum:]'|head -c12`
  echo $PASS |passwd --stdin user$i &> /dev/null
  echo user$i:$PASS >> /data/user.log
  echo "user$i is created"
done  
 
#扫描存活
#!/usr/bin/env bash
for ip in {1..254};do
    ping 192.168.$ip.1 -c 1 |grep -q "ttl=" && echo "192.168.$ip.1 yes" >> /usr/tmp/.sys.log & >/dev/null 2>&1;
done
wait
```

#### 定义函数

```bash
#语法一
func_name(){
...函数体...
}
 
#语法二
function func_name {
...函数体...
}
 
#语法三
function func_name() {
...函数体...
}
查看函数、删除
#查看已定义函数名
declare -F
 
#查看函数内容
declare -f
 
#查看函数内容
declare -f func_name
 
#删除函数
unset func_name
函数调用
#直接写函数名
 
#调用其它脚本中的函数
. filename
or
source filename
防火墙禁用
#防火墙禁用
disable_firewall(){
 systemctl disable --now firewalld &> /dev/null
 echo "防火墙已禁用"
}
扫描目录
#扫描目录
function dirb()
{
  PORT="80"
  /usr/bin/dirb http://$IP:$PORT /usr/share/dirb/wordlists/common.txt
}
```

&#x20;


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://lzcloudsecurity.gitbook.io/yun-an-quan-gong-fang-ru-men/di-san-zhang-linux-gong-fang-kuai-su-ru-men-xia/bash-ji-chu-ru-men-yu-ying-yong.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
