shell编程
作者:互联网
Shell编程入坑
Shell简介
Shell是一个用C语言编写的程序,它是用户使用linux的桥梁,Shell既是一种命令语言,又是一种程序设计语言。
Shell语法与php类似,容易上手
感觉这个语言蛮有意思的,在linux上写一些自动化脚本挺不错的。结合了菜鸟教程和网上视频简单学了学。
第一个Shell脚本
#! /bin/bash
echo "this is my first shell program!"
result:this is my first shell program!
#!
用来告诉系统这个脚本需要什么解释器来执行,即使用哪一种shell,如果是python脚本,开头可以写上#! /usr/bin/python
,即表示用python解释器来执行- echo命令用于向窗口输出文本
运行Shell脚本的方法:
- 作为可执行程序
将上述代码保存为hello.sh(文本后缀对linux来说没有太大意义,其实该后缀可以任意修改,仍然可以正常运行),通过命令行cd到相应的目录,为该脚本赋予可执行权限后,通过./hello.sh的方式即可执行脚本
chmod +x hello.sh
./hello.sh
需要注意的是:
- 只能通过./test.sh去运行,而不能通过文件名test.sh去运行。直接写 test.sh,linux 系统会去 PATH 里寻找有没有叫 test.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,当前的目录通常不会在PATH里,所以直接输入test.sh 会显示找不到命令,要用./test.sh告诉系统,就在当前目录找。
- 该方法会打开一个子shell读取并执行hello.sh中的命令
直接输入hello.sh的结果:
┌──(root㉿kali)-[/home/kali/桌面]
└─# hello.sh
hello.sh: command not found
当然如果要让系统找到该文件,也可以直接输入绝对路径,这样也能成功执行脚本,例如:
┌──(root㉿kali)-[/home/kali/桌面]
└─# /home/kali/桌面/hello.sh
this is my first shell program!
-
作为解释器参数
直接运行解释器,作用的参数为shell脚本名,文件可以无执行权限。例如:
/bin/sh hello.sh # 运行shell脚本 /usr/bin/python hello.py # 运行python脚本
该方法会打开一个子shell来读取并执行hello.sh中的命令
- 其他方式
使用source hello.sh
或者. hello.sh
(bash特有)方式,其作用是在当前shell环境下读取并执行hello.sh脚本中的命令,文件可以无执行权限。
BASH
cat /etc/shells,可以查看当前系统可以使用哪些shell
echo $SHELL 可以查看自己当前使用的是什么shell
以下将使用kali中的bash命令行作为示例(kali默认使用的shell是zsh,在命令行中输入bash即可进入使用bash的子shell进程中
以下内容仅适用于适用bash的命令行
- bash是linux其中一种命令处理器,运行在文本窗口中,并能执行用户直接输入的命令
- bash还能从文件中读取linux命令,称之为脚本
- bash支持通配符、管道、命令替换、条件判断等逻辑控制语句
命令历史
Shell会保留其会话中用户提交执行的命令
history
-c 清空内存中命令历史
-r 从文件中恢复历史命令
数字 :显示最近n条命令 例如: history 10
echo $HISTSIZE # 显示保留历史的条数
# 存放用户执行的历史命令,写入文件
┌──(root㉿kali)-[/home/kali]
└─# echo $HISTFILE
/root/.bash_history
# kali使用的是zsh ,所以保存路径为 /root/.zsh_history
# 调用历史记录
![历史id] 可以快速执行历史命令
!! 执行上次历史命令
bash特性汇总
- 文件路径、命令tab键补全
- 快捷键 ctrl +a,e,u,k,l
- 通配符
- 命令历史
- 命令别名
- 命令行展开
变量
变量基本内容
- 变量定义与赋值,注意变量与值之间不得有空格
以下赋值方式都是可以的
name="123"
name=123
name='123'
shell默认把所有变量都认为是字符串
shell变量是弱类型,无需事先声明类型,是将声明和赋值同时进行变量替换/引用
┌──(root㉿kali)-[/home/kali]
└─# name="123"
┌──(root㉿kali)-[/home/kali]
└─# echo $name # 可以在变量名前加$符号
123
┌──(root㉿kali)-[/home/kali]
└─# echo ${name} # 比较完整的是前面加$,变量名再用{}包裹,加花括号是为了帮助解释器识别变量的边界
123
'x',"x",x,`x`
- 单引号:所见即所得,是强引用
- 双引号:输出引号里所有的内容,识别特殊符号,弱引用
- 无引号:连续的符号可以不加引号,有空格则有歧义,最好使用双引号
- 反引号,引用命令执行结果,等于$()用法
┌──(kali㉿kali)-[~/桌面]
└─$ num1=1
┌──(kali㉿kali)-[~/桌面]
└─$ num2=2
┌──(kali㉿kali)-[~/桌面]
└─$ num3="$num1"
┌──(kali㉿kali)-[~/桌面]
└─$ echo $num3
1
┌──(kali㉿kali)-[~/桌面]
└─$ num4='$num2'
┌──(kali㉿kali)-[~/桌面]
└─$ echo $num4
$num2
`linux命令` # echo 这个值会直接运行该linux命令
┌──(root㉿kali)-[/home/kali/桌面]
└─# name=`whoami`
┌──(root㉿kali)-[/home/kali/桌面]
└─# echo $name
root
-
变量名规则
-
不得引用保留关键字(help查看关键字)
-
只能包含数字、字母、下划线
-
不能以数字开头
-
不能用标点符号
-
变量名严格区分大小写
-
变量作用域
可以发现在当前shell中定义的变量在子shell(在当前shell中输入想要使用的shell名字,比如zsh,bash,sh,即可进入子shell中无法引用,同样的,子shell中定义的变量也无法在当前shell中引用,因为作用域的缘故。
- 环境变量,也称为全局变量,针对当前shell及其任意子进程,环境变量也分 '自定义'、'内置环境变量',如$PATH就是内置环境变量
- 局部变量,针对在shell函数或是shell脚本中定义
- 位置参数变量:用于shell脚本中传递的参数
- 特殊变量:shell内置的特殊功效变量,如:
- $? #作用:判断上一行命令执行是否成功
- 0:成功
- 1-255:错误码
- $? #作用:判断上一行命令执行是否成功
- 自定义 变量
父子shell
-
每次调用bash/sh解释器执行脚本,都会开启一个子shell,因此不保留脚本运行过程中的shell变量
-
通过pstree命令可以检查进程树,查看当前使用的shell的父子情况
-
调用source或者. 等方式执行脚本是在当前shell环境加载脚本,因此保留变量
环境变量设置
-
环境变量一般指的是用
export
内置命令导出的变量,用于定义shell的运行环境、保证shell命令的正确执行。shell通过环境变量确定登录的用户名,PATH路径、文件系统等各种应用。 -
环境变量可以在命令行中临时创建,但是用户退出shell终端,变量即丢失,如要永久生效,需要修改
环境变量配置文件
。- 用户个人配置文件
~/.bash_profile
、~/.bashrc 远程登录用户特有文件
- 用户个人配置文件
- 全局配置文件
/etc/profile
,/etc/bashrc
,且系统建议最好创建在/etc/profile.d/
,而非直接修改主文件,修改全局配置文件,影响所有登录系统的用户
- 每个用户都有自己的环境变量配置文件,
~/.bash_profile
和.bashrc
,每个用户中的环境变量只在自己的shell终端中生效,每次写入新的环境变量后,需重新登录才能加载新写入的环境变量 - 当需要让所有用户都可以使用某个变量,可以将其写入全局环境变量配置文件,即
/etc/profile
检查系统环境变量的命令
命令 | 作用 |
---|---|
set | 输出所有变量,包括全局变量、局部变量 |
env | 只显示全局变量 |
declare | 输出所有的变量,如同set |
export | 显示和设置环境变量值 |
撤销环境变量
- unset变量名,删除变量或函数
设置只读变量
- readonly,只有shell结束,只读变量失效
┌──(root㉿kali)-[/home/kali/桌面]
└─# readonly passwd=123
┌──(root㉿kali)-[/home/kali/桌面]
└─# echo $passwd
123
┌──(root㉿kali)-[/home/kali/桌面]
└─# passwd=234
bash: passwd:只读变量
系统保留环境变量关键字
-
bash内嵌了诸多环境变量,用于定义bash的工作环境
通过下面命令可以查看:
export |awk -F '[ :=]' '{print $3}' >env cat env
result:
COLORTERM
COMMAND_NOT_FOUND_INSTALL_PROMPT
DISPLAY
DOTNET_CLI_TELEMETRY_OPTOUT
HOME
LANG
LANGUAGE
LESS_TERMCAP_mb
LESS_TERMCAP_md
LESS_TERMCAP_me
LESS_TERMCAP_se
LESS_TERMCAP_so
LESS_TERMCAP_ue
LESS_TERMCAP_us
LOGNAME
LS_COLORS
MAIL
OLDPWD
PATH
POWERSHELL_TELEMETRY_OPTOUT
POWERSHELL_UPDATECHECK
PWD
SHELL
SHLVL
SUDO_COMMAND
SUDO_GID
SUDO_UID
SUDO_USER
TERM
USER
XAUTHORITY
环境变量加载顺序
- ssh登录Linux后,系统启动一个bash,bash会读取若干个系统文件环境文件,检查环境变量设置
- /etc/profile:全局环境变量文件为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行,并从/etc/profile.d目录的配置文件中搜集shell的设置。
- 然后读取/etc/profile.d目录下的脚本,有系统诸多脚本,也放入自定义需要登录加载的脚本,便于用于登录后立即运行脚本
- 运行$HOME/.bash_profile(用户环境变量文件)
- 运行$HOME/.bashrc
- 最终运行/etc/bashrc
特殊变量
在命令行中输入
man sh
,查找Special Parameters,即可看到部分特殊变量
参数处理 | 说明 |
---|---|
$0 | 获取shell脚本文件名,以及脚本路径 |
$n | 获取shell脚本传递的第n个参数,n在1-9之间,如$1、$2、$9,大于则需要写,${10},参数空格隔开 |
$# | 传递到脚本的参数个数 |
$* | 以一个单字符串显示所有向脚本传递的参数。 如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。 |
$$ | 脚本运行的当前进程ID号 |
$! | 后台运行的最后一个进程的ID号 |
$@ | 与$*相同,但是使用时加引号,并在引号中返回每个参数。 如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。 |
$_ | 在此之前执行的命令的最后一个参数 |
$- | 显示Shell使用的当前选项,与set命令功能相同。 |
$? | 显示最后命令的退出状态。0表示没有错误,其他任何值(1-255)表明有错误。 |
运行如下特殊变量.sh文件:
┌──(root㉿kali)-[/home/kali/桌面]
└─# cat 特殊变量.sh
#! /bin/bash
echo -e "\n" # 使用-e参数可以输出转义字符
echo '$n'
echo "文件名为:$0"
echo "第一个参数:$1"第二个参数:$2"第三个参数:$3"
echo -e "\n"
echo '$#'
echo "参数个数为:$#"
echo -e "\n"
echo '$$'
echo "该文件运行的PID为$$"
echo -e "\n"
echo '$*'
echo "所有参数为:$*"
echo -e "\n"
echo '$@'
echo "所有参数为:$@"
结果:
┌──(root㉿kali)-[/home/kali/桌面]
└─# ./特殊变量.sh a b c
$n
文件名为:./参数传递.sh
第一个参数:a第二个参数:b第三个参数:c
$#
参数个数为:3
$$
该文件运行的PID为40241
$*
所有参数为:a b c
$@
所有参数为:a b c
$_
运行上述脚本后,输出$_
┌──(root㉿kali)-[/home/kali/桌面]
└─# echo $_
c
$!
┌──(root㉿kali)-[/home/kali/桌面]
└─# nohup ping www.baidu.com & 1>/dev/hull
[1] 49488
┌──(root㉿kali)-[/home/kali/桌面]
└─# nohup: 忽略输入并把输出追加到'nohup.out'
echo $!
49488
┌────(root㉿kali)-[/home/kali/桌面]
└─# kill -9 $!
┌────(root㉿kali)-[/home/kali/桌面]
└─# [1]+ 已杀死 nohup ping www.baidu.com
$*与$@的区别
当 $* 和 $@ 不被双引号 " " 包围时,它们之间没有任何区别,都是将接收到的每个参数看做一份数据,彼此之间以空格来分隔。
但是当它们被双引号" "包含时,就会有区别了:
- "$*"会将所有的参数从整体上看做一份数据,而不是把每个参数都看做一份数据;
- "$@"仍然将每个参数都看作一份数据,彼此之间是独立的。
比如传递了 5 个参数,那么对于 $* 来说,这 5 个参数会合并到一起形成一份数据,它们之间是无法分割的;而对于 $@ 来说,这 5 个参数是相互独立的,它们是 5 份数据。
如果使用 echo 直接输出 $* 和 $@ 做对比,是看不出区别的;但如果使用 for 循环来逐个输出数据,立即就能看出区别来。
运行如下test.sh文件
┌──(root㉿kali)-[/home/kali/桌面]
└─# cat test.sh
#! /bin/bash
echo "params from $* "
for _ in "$*";do
echo $_
done
echo "params from $@ "
for _ in "$@";do
echo $_
done
结果:
┌──(root㉿kali)-[/home/kali/桌面]
└─# ./test.sh a b c
params from a b c
a b c
params from a b c
a
b
c
标签:shell,kali,编程,echo,sh,root,bash 来源: https://www.cnblogs.com/jackie-lee/p/16643515.html