ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

shell编程

2022-08-31 16:30:52  阅读:287  来源: 互联网

标签:shell kali 编程 echo sh root bash


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

需要注意的是:

  1. 只能通过./test.sh去运行,而不能通过文件名test.sh去运行。直接写 test.sh,linux 系统会去 PATH 里寻找有没有叫 test.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,当前的目录通常不会在PATH里,所以直接输入test.sh 会显示找不到命令,要用./test.sh告诉系统,就在当前目录找。
  2. 该方法会打开一个子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查看关键字)

  • 只能包含数字、字母、下划线

  • 不能以数字开头

  • 不能用标点符号

  • 变量名严格区分大小写

  • 变量作用域

    image-20220828203355577

    可以发现在当前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环境加载脚本,因此保留变量

环境变量设置

  1. 环境变量一般指的是用export内置命令导出的变量,用于定义shell的运行环境、保证shell命令的正确执行。shell通过环境变量确定登录的用户名,PATH路径、文件系统等各种应用。

  2. 环境变量可以在命令行中临时创建,但是用户退出shell终端,变量即丢失,如要永久生效,需要修改环境变量配置文件

    • 用户个人配置文件 ~/.bash_profile~/.bashrc 远程登录用户特有文件
  • 全局配置文件/etc/profile/etc/bashrc,且系统建议最好创建在/etc/profile.d/,而非直接修改主文件,修改全局配置文件,影响所有登录系统的用户
  1. 每个用户都有自己的环境变量配置文件,~/.bash_profile.bashrc,每个用户中的环境变量只在自己的shell终端中生效,每次写入新的环境变量后,需重新登录才能加载新写入的环境变量
  2. 当需要让所有用户都可以使用某个变量,可以将其写入全局环境变量配置文件,即/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

环境变量加载顺序

  1. ssh登录Linux后,系统启动一个bash,bash会读取若干个系统文件环境文件,检查环境变量设置
  2. /etc/profile:全局环境变量文件为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行,并从/etc/profile.d目录的配置文件中搜集shell的设置。
  3. 然后读取/etc/profile.d目录下的脚本,有系统诸多脚本,也放入自定义需要登录加载的脚本,便于用于登录后立即运行脚本
  4. 运行$HOME/.bash_profile(用户环境变量文件)
  5. 运行$HOME/.bashrc
  6. 最终运行/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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有