linux pwn 相关工具

news2024/10/5 14:02:00

环境搭建

虚拟机安装

  • 镜像下载网站
  • 为了避免环境问题建议 22.04 ,20.04,18.04,16.04 等常见版本 ubuntu 虚拟机环境各准备一份。注意定期更新快照以防意外。
  • 虚拟机建议硬盘 256 G 以上,内存也尽量大一些。硬盘大小只是上界,256 G 不是真就占了 256 G,而后期如果硬盘空间不足会很麻烦。

基础工具

vim

sudo apt install vim

gedit

不习惯 vim 的可以使用 gedit 文本编辑器。

sudo apt install gedit

git

sudo apt install git

gcc

sudo apt install gcc

python

ipython 提供了很好的 python 交互命令行,建议安装。

sudo apt install python2 ipython2
sudo apt install python3 ipython3

另外有的版本 ubuntu 的不好安装 pip2 可以使用 get-pip.py 脚本安装。

curl https://bootstrap.pypa.io/get-pip.py --output get-pip.py
sudo python2 get-pip.py

pwn 相关工具

gdb

sudo apt-get install gdb gdb-multiarch

pwntools

注意我这里的 pwntools 是 python2 版本的。

pip install pwntools

这样安装的 pwntools 的 plt 功可能无法正常使用,需要手动安装 Unicorn 库。

pip install unicorn==1.0.3

gdb 插件

主要有 pwndbg,peda,gef ,这里我常用的是 pwndbg 。对于一些版本过于古老导致环境装不上的可以尝试一下 peda 。

先将三个项目的代码都拉取下来。

git clone https://github.com/longld/peda.git
git clone https://github.com/pwndbg/pwndbg.git
git clone https://github.com/hugsy/gef.git

pwndbg 需要运行初始化脚本。

cd pwndbg & sudo ./setup.sh

另外还有一个 pwngdb 插件在调试多线程堆(heapinfoall 命令)的时候很有用,建议安装。

git clone https://github.com/scwuaptx/Pwngdb.git 

gdb 在启动的时候会读取当前用户的主目录的 .gdbinit 文件进行 gdb 插件的初始化,这里提供一个配置方案。

source /home/sky123/tools/pwndbg/gdbinit.py 
#source /home/sky123/tools/peda/peda.py
#source /home/sky123/tools/gef/gef.py


#source /home/sky123/tools/muslheap/muslheap.py

source /home/sky123/tools/Pwngdb/pwngdb.py
source /home/sky123/tools/Pwngdb/angelheap/gdbinit.py

define hook-run
python
import angelheap
angelheap.init_angelheap()
end
end

注意,以普通用权限和管理员权限启动 gdb 时读取的 .gdbinit 文件的路径是不同的,普通权限读取的是 /home/<username>/.gdbinit 而管理员权限读取的是 /root/.gdbinit

gadget 搜索工具

ROPgdbget

安装:

git clone https://github.com/JonathanSalwan/ROPgadget.git
cd ROPgadget
sudo python3 setup.py install

使用:

 ROPgadget --binary ntdll.dll > rop

ropper

  • 安装:
    • 在 pypi 的 ropper 官网上下载 ropper
    • 运行安装脚本完成 ropper 安装
      python setup.py install
      
  • 使用:
    ropper --file ./pwn --nocolor > rop
    

one_gadget

用于搜索 libc 中能够实现 execve("/bin/sh", (char *[2]) {"/bin/sh", NULL}, NULL); 的效果的跳转地址,由于是采用特征匹配的方法,因此只能是在 libc 中查找。

  • 安装:
    sudo apt install -y ruby ruby-dev
    sudo gem install one_gadget
    
  • 使用:可以查找到 gadget 地址以及条件限制。
    ➜  ~ one_gadget /lib/x86_64-linux-gnu/libc.so.6
    0x50a37 posix_spawn(rsp+0x1c, "/bin/sh", 0, rbp, rsp+0x60, environ)
    constraints:
      rsp & 0xf == 0
      rcx == NULL
      rbp == NULL || (u16)[rbp] == NULL
    
    0xebcf1 execve("/bin/sh", r10, [rbp-0x70])
    constraints:
      address rbp-0x78 is writable
      [r10] == NULL || r10 == NULL
      [[rbp-0x70]] == NULL || [rbp-0x70] == NULL
    
    0xebcf5 execve("/bin/sh", r10, rdx)
    constraints:
      address rbp-0x78 is writable
      [r10] == NULL || r10 == NULL
      [rdx] == NULL || rdx == NULL
    
    0xebcf8 execve("/bin/sh", rsi, rdx)
    constraints:
      address rbp-0x78 is writable
      [rsi] == NULL || rsi == NULL
      [rdx] == NULL || rdx == NULL
    

如果 one_gadget 在一个版本的 Ubuntu 中搜索某一版本的glibc 的 gadget 出现如下报错可以尝试换另一个版本的 Ubuntu ,具体原因未知。
在这里插入图片描述

seccomp-tools

用于查看和生成程序沙箱规则。

  • 安装:
    sudo gem install seccomp-tools
    
  • 使用:
    seccomp-tools dump ./pwn
    

LibcSearcher

通过泄露的 libc 中函数的地址来确定 libc 版本。

git clone https://github.com/lieanu/LibcSearcher.git
cd LibcSearcher
sudo python3 setup.py install

patchelf

安装:

sudo apt install patchelf

qemu

sudo apt install qemu-user qemu-system 

工具使用

vim

功能

命令行模式下的文本编辑器。

  • 根据文件扩展名自动判别编程语言。支持代码缩进、代码高亮等功能。
  • 使用方式:vim filename
    • 如果已有该文件,则打开它。
    • 如果没有该文件,则打开个一个新的文件,并命名为 filename

模式

  • 一般命令模式
    默认模式,按不同字符即可进行不同操作。可以复制、粘贴、删除文本等。
  • 编辑模式
    • 在一般命令模式里按下 i ,会进入编辑模式。
    • 按下 Esc 会退出编辑模式,返回到一般命令模式。
  • 命令行模式
    • 在一般命令模式里按下 :/? 三个字母中的任意一个,会进入命令行模式。命令行在最下面。
    • 可以查找、替换、保存、退出、配置编辑器等。

操作

  • i:进入编辑模式。
  • Esc:进入一般命令模式。
  • h:光标向左移动一个字符。
  • j:光标向下移动一个字符。
  • k:光标向上移动一个字符。
  • l 或 :光标向右移动一个字符。
  • n<Space>n 表示数字,按下数字后再按空格,光标会向右移动这一行的 n 个字符。
  • 0功能键[Home]:光标移动到本行开头。
  • $功能键[End]:光标移动到本行末尾。
  • G:光标移动到最后一行。
  • :nnGn 为数字,光标移动到第 n 行。
  • gg:光标移动到第一行,相当于1G
  • n<Enter>n 为数字,光标向下移动 n 行。
  • /word:向光标之下寻找第一个值为 word 的字符串。
  • ?word:向光标之上寻找第一个值为 word 的字符串。
  • n:重复前一个查找操作。
  • N:反向重复前一个查找操作。
  • :n1,n2s/word1/word2/gn1n2 为数字,在第 n1 行与 n2 行之间寻找 word1 这个字符串,并将该字符串替换为 word2
  • :1,$s/word1/word2/g:将全文的 word1 替换为 word2
  • :1,$s/word1/word2/gc:将全文的 word1 替换为 word2 ,且在替换前要求用户确认。
  • v:选中文本。
  • d:删除选中的文本。
  • dd: 删除当前行。
  • y:复制选中的文本。
  • yy: 复制当前行。
  • p: 将复制的数据在光标的下一行/下一个位置粘贴。
  • u:撤销。
  • Ctrl + r:取消撤销。
  • >:将选中的文本整体向右缩进一次。
  • <:将选中的文本整体向左缩进一次。
  • :w:保存。
  • :w!:强制保存。
  • :q:退出。
  • :q!:强制退出。
  • :wq:保存并退出。
  • :set paste:设置成粘贴模式,取消代码自动缩进。
  • :set nopaste:取消粘贴模式,开启代码自动缩进。
  • :set nu:显示行号。
  • :set nonu:隐藏行号。
  • gg=G:将全文代码格式化。
  • :noh:关闭查找关键词高亮。
  • Ctrl + q:当 vim 卡死时,可以取消当前正在执行的命令。

异常处理

每次用 vim 编辑文件时,会自动创建一个 .filename.swp 的临时文件。如果打开某个文件时,该文件的 swp 文件已存在,则会报错。此时解决办法有两种:

  • 找到正在打开该文件的程序,并退出。
  • 直接删掉该 swp 文件即可。

shell

概论

Linux 中常见的 shell 脚本有很多种,常见的有:

  • Bourne Shell (/usr/bin/sh/bin/sh)
  • Bourne Again Shell (/bin/bash)
  • C Shell (/usr/bin/csh)
  • K Shell (/usr/bin/ksh)
  • zsh (/usr/bin/zsh)

  • Linux 系统中一般默认使用 bash ,所以接下来讲解 bash 中的语法。文件开头需要写 #! /bin/bash ,指明 bash 为脚本解释器。

注意,不同的 shell 之间语法并不完全兼容,因此需要按照说明用指定的 shell 解释器运行 shell 。

注释

单行注释

每行中 # 之后的内容均是注释。

多行注释

格式:

: <<EOF
第一行注释
第二行注释
第三行注释
EOF

其中 EOF 可以换成其它任意字符串。例如:

: <<abc
第一行注释
第二行注释
第三行注释
abc

: <<!
第一行注释
第二行注释
第三行注释
!

变量

定义变量

定义变量,不需要加 $ 符号,例如:

name1='abc' # 单引号定义字符串
name2="abc" # 双引号定义字符串
name3=abc   # 也可以不加引号,同样表示字符串

注意:

  • 等号两侧不能有空格。
  • 等号左边的变量认为是定义,不能加 $,等号右侧使用的变量要加 $
    name=abc
    name=${name}def
    echo $name # abcdef
    

使用变量

使用变量,需要加上 $ 符号,或者 ${} 符号。花括号是可选的,主要为了帮助解释器识别变量边界。

name=abc
echo $name      # 输出 abc
echo ${name}    # 输出 abc
echo ${name}def # 输出 abcdef

只读变量

使用 readonly 或者 declare 可以将变量变为只读。

name=abc
readonly name
declare -r name # 两种写法均可

name=def        # 会报错,因为此时name只读

删除变量

unset 可以删除变量。

name=abc
unset name
echo $name # 输出空行

变量类型

  • 自定义变量(局部变量):子进程不能访问的变量。
  • 环境变量(全局变量):子进程可以访问的变量。

自定义变量改成环境变量:

name=abc        # 定义变量
export name     # 第一种方法
declare -x name # 第二种方法

环境变量改为自定义变量:

export name=abc # 定义环境变量
declare +x name # 改为自定义变量

效果如下:

$ export a=abc
$ echo $a
abc
$ bash
$ echo $a
abc
$ declare +x a
$ echo $a
abc
$ bash
$ echo $a

字符串

字符串可以用单引号,也可以用双引号,也可以不加引号。

单引号,双引号和不加引号的区别:

  • 单引号中的内容会原样输出,不会执行、不会取变量。
  • 双引号中的内容可以执行、可以取变量,相当于把变量的值和表达式的结果都拼接到字符串中
  • 不加引号相当于把变量的值和表达式的结果拼接到 shell 语句中执行
  • 双引号内的单引号不需要转义,单引号内的双引号同样不需要转义。
name=abc                 # 不用abc引号
echo 'hello, $name "hh"' # 单引号字符串,输出 hello, $name "hh"
echo "hello, $name 'hh'" # 双引号字符串,输出 hello, abc 'hh'

获取字符串长度:

name="abc"
echo ${#name} # 输出3

提取子串:

name="abcdefgh"
echo ${name:2:5} # 提取从 2 开始的 5 个字符 "cdefg"

默认变量

文件参数变量

在执行 shell 脚本时,可以向脚本传递参数。$1 是第一个参数,$2 是第二个参数,以此类推。特殊的,$0 是文件名(包含路径)。例如:

创建文件 test.sh

#! /bin/bash

echo "文件名:"$0
echo "第一个参数:"$1
echo "第二个参数:"$2
echo "第三个参数:"$3
echo "第四个参数:"$4

然后执行该脚本:

$ chmod +x test.sh 
$ ./test.sh 1 2 3 4
文件名:./test.sh
第一个参数:1
第二个参数:2
第三个参数:3
第四个参数:4

其它参数相关变量:

参数说明
$#代表文件传入的参数个数,如上例中值为 4 。
$*由所有参数构成的用空格隔开的字符串,如上例中值为 "$1 $2 $3 $4"
$@每个参数分别用双引号括起来的字符串,如上例中值为 "$1" "$2" "$3" "$4"
$$脚本当前运行的进程 ID 。
$?上一条命令的退出状态(注意不是 stdout,而是 exit code),0 表示正常退出,其他值表示错误。
$(command)返回 command 这条命令的 stdout(可嵌套)。
`command`返回 command 这条命令的 stdout(不可嵌套)

数组

数组中可以存放多个不同类型的值(数组除外),只支持一维数组,初始化时不需要指明数组大小。数组下标从 0 开始。

定义

数组用小括号表示,元素之间用空格隔开。例如:

array=(abc 123 "def" 456)

也可以直接定义数组中某个元素的值:

array[0]=abc
array[1]=123
array[2]="def"
array[3]=456

读取数组中某个元素的值

格式如下:

${array[index]}

例如:

array=(abc 123 "def" 456)
echo ${array[0]}
echo ${array[1]}
echo ${array[2]}
echo ${array[3]}

读取整个数组

格式:

${array[@]}  # 第一种写法
${array[*]}  # 第二种写法

例如:

array=(abc 123 "def" 456)
array[3000]=789

echo ${array[@]} # 第一种写法,输出 abc 123 def 456 789
echo ${array[*]} # 第二种写法,输出 abc 123 def 456 789

数组长度

类似于字符串:

${#array[@]}  # 第一种写法
${#array[*]}  # 第二种写法

例如:

array=(abc 123 "def" 456)
array[3000]=789

echo ${#array[@]} # 第一种写法,输出 5
echo ${#array[*]} # 第二种写法,输出 5

expr 命令

expr 命令用于求表达式的值,格式为:expr 表达式

表达式说明:

  • 用空格隔开每一项。
  • 用反斜杠放在 shell 特定的字符前面(发现表达式运行错误时,可以试试转义或者加 ""'')。
  • 对包含空格和其他特殊字符的字符串要用引号括起来。
  • expr 会在 stdout 中输出结果。如果为逻辑关系表达式,则结果为真时,stdout 输出 1 ,否则输出 0 。
  • expr 的 exit code:如果为逻辑关系表达式,则结果为真时,exit code 为 0,否则为 1 。

字符串表达式

  • length STRING:返回 STRING 的长度。
  • index STRING CHARSETCHARSET 中任意单个字符在 STRING 中最前面的字符位置,下标从 1 开始。如果在 STRING 中完全不存在 CHARSET 中的字符,则返回 0 。
  • substr STRING POSITION LENGTH:返回 STRING 字符串中从 POSITION (下标从 1 开始)开始,长度最大为 LENGTH 的子串。如果 POSITIONLENGTH 为负数,0 或非数值,则返回空字符串。

示例:

str="Hello World!"

echo $(expr length "$str")     # ``不是单引号,表示执行该命令,输出 12
echo $(expr index "$str" aWd)  # 输出 7,下标从 1 开始
echo $(expr substr "$str" 2 3) # 输出 ell

整数表达式

expr 支持普通的算术操作,算术表达式优先级低于字符串表达式,高于逻辑关系表达式。

  • + -:加减运算。两端参数会转换为整数,如果转换失败则报错。
  • * / %:乘,除,取模运算。两端参数会转换为整数,如果转换失败则报错。
  • ():可以改变优先级,但需要用反斜杠转义。

示例:

a=3
b=4

echo `expr $a + $b`  # 输出7
echo `expr $a - $b`  # 输出-1
echo `expr $a \* $b`  # 输出12,*需要转义
echo `expr $a / $b`  # 输出0,整除
echo `expr $a % $b` # 输出3
echo `expr \( $a + 1 \) \* \( $b + 1 \)`  # 输出20,值为(a + 1) * (b + 1)

逻辑关系表达式

  • |:如果第一个参数非空且非 0 ,则返回第一个参数的值,否则返回第二个参数的值,但要求第二个参数的值也是非空或非 0 ,否则返回 0 。如果第一个参数是非空或非 0 时,不会计算第二个参数。
  • &:如果两个参数都非空且非 0 ,则返回第一个参数,否则返回 0 。如果第一个参为 0 或为空,则不会计算第二个参数。
  • < <= = == != >= >:比较两端的参数,如果为 true ,则返回 1 ,否则返回 0 。=== 的同义词。expr 首先尝试将两端参数转换为整数,并做算术比较,如果转换失败,则按字符集排序规则做字符比较。
  • ():可以改变优先级,但需要用反斜杠转义
a=3
b=4
echo $(expr $a \> $b)   # 输出 0,>需要转义
echo $(expr $a '<' $b)  # 输出 1,也可以将特殊字符用引号引起来
echo $(expr $a '>=' $b) # 输出 0
echo $(expr $a \<\= $b) # 输出 1

c=0
d=5
echo $(expr $c \& $d) # 输出 0
echo $(expr $a \& $b) # 输出 3
echo $(expr $c \| $d) # 输出 5
echo $(expr $a \| $b) # 输出 3

read 命令

read 命令用于从标准输入中读取单行数据。当读到文件结束符时,exit code 为 1 ,否则为 0 。

参数说明

  • -p: 后面可以接提示信息
  • -t:后面跟秒数,定义输入字符的等待时间,超过等待时间后会自动忽略此命令

实例:

sky123@ubuntu:~$ read -p "Please input your name: " -t 30 name
Please input your name: sky123
sky123@ubuntu:~$ echo $name
sky123

echo 命令

echo 用于输出字符串。命令格式:echo STRING

显示换行

-e 开启转义,单双引号内均会转义。

echo -e 'a\nb\nc\n'

输出结果:

a
b
c

显示不换行

-e 开启转义,\c 不换行。

echo -e "a\c"
echo -e 'b\c'
echo -e c

输出结果:

abc

printf 命令

printf 命令用于格式化输出,类似于 C/C++ 中的 printf 函数。
命令格式:printf format-string [arguments...]

sky123@sky123:~$ a=`printf "%10lf" 123`
sky123@sky123:~$ echo $a
123.000000

test 命令与判断符号 []

逻辑运算符 && 和 ||

  • && 表示与,|| 表示或
  • 二者具有短路原则:
    • expr1 && expr2:当 expr1 为假时,直接忽略 expr2
    • expr1 || expr2:当 expr1 为真时,直接忽略 expr2
  • 表达式的 exit code 为 0 ,表示真;为非零,表示假。(与 C/C++ 中的定义相反)

test 命令

在命令行中输入 man test ,可以查看 test 命令的用法。

  • test 命令用于判断文件类型,以及对变量做比较。
  • test 命令用 exit code 返回结果,而不是使用 stdout 。0 表示真,非 0 表示假。

例如:

sky123@sky123:~$ test 2 -lt 3 # 为真,返回值为 0
sky123@sky123:~$ echo $? # 输出上个命令的返回值,输出 0
0

test 命令常与短路原则结合,下面这条命令可以判断文件 test.sh 是否存在。

test -e test.sh && echo "exist" || echo "Not exist"

test 的判断参数:

  • 文件类型判断,命令格式: test -e filename(判断文件是否存在)
测试参数代表意义
-e文件是否存在
-f是否为文件
-d是否为目录
  • 文件权限判断,命令格式:test -r filename(判断文件是否可读)
测试参数代表意义
-r文件是否可读
-w文件是否可写
-x文件是否可执行
-s是否为非空文件
  • 整数间的比较,命令格式:test $a -eq $ba 是否等于 b
测试参数代表意义
-eqa 是否等于 b
-nea 是否不等于 b
-gta 是否大于 b
-lta 是否小于 b
-gea 是否大于等于 b
-lea 是否小于等于 b
  • 字符串比较
测试参数代表意义
test -z STRING判断 STRING 是否为空,如果为空,则返回 true
test -n STRING判断 STRING 是否非空,如果非空,则返回 true(-n 可以省略)
test str1 == str2判断 str1 是否等于 str2
test str1 != str2判断 str1 是否不等于 str2
  • 多重条件判定,命令格式:test -r filename -a -x filename
测试参数代表意义
-a两条件是否同时成立
-o两条件是否至少一个成立
!取反。如 test ! -x file,当 file 不可执行时,返回 true

判断符号[]

[]test 用法几乎一模一样,更常用于 if 语句中。另外 [[]][] 的加强版,支持的特性更多。

例如:

sky123@sky123:~$ [ 2 -lt 3 ]  # 为真,返回值为 0
sky123@sky123:~$ echo $? # 输出上个命令的返回值,输出 0
0

[] 命令同样可以与短路原则结合,下面这条命令可以判断文件 test.sh 是否存在。

[ -e test.sh ] && echo "exist" || echo "Not exist"

注意:

  • [] 内的每一项都要用空格隔开
  • 中括号内的变量,最好用双引号括起来
  • 中括号内的常数,最好用单或双引号括起来
name="123 456"
[ $name == "123 456" ]  # 错误,等价于 [ 123 456 == "123 456" ],参数太多
[ "$name" == "123 456" ]  # 正确

判断语句

if…then 形式

类似于 C/C++ 中的 if-else 语句。

  • 单层 if
    • 命令格式:
      if condition; then
          语句1
          语句2
          ...
      fi
      
    • 示例:
      a=3
      b=4
      
      if [ "$a" -lt "$b" ] && [ "$a" -gt 2 ]; then
          echo ${a}在范围内
      fi
      
    • 输出结果:
      3在范围内
      
  • 单层 if-else
    • 命令格式
      if condition; then
          语句1
          语句2
          ...
      else
          语句1
          语句2
          ...
      fi
      
    • 示例:
      a=3
      b=4
      
      if ! [ "$a" -lt "$b" ]; then
          echo ${a}不小于${b}
      else
          echo ${a}小于${b}
      fi
      
    • 输出结果:
      3小于4
      
  • 多层 if-elif-elif-else
    • 命令格式
      if condition; then
          语句1
          语句2
          ...
      elif condition; then
          语句1
          语句2
          ...
      elif condition; then
          语句1
          语句2
      else
          语句1
          语句2
          ...
      fi
      
    • 示例:
      a=4
      
      if [ $a -eq 1 ]; then
          echo ${a}等于1
      elif [ $a -eq 2 ]; then
          echo ${a}等于2
      elif [ $a -eq 3 ]; then
          echo ${a}等于3
      else
          echo 其他
      fi
      
  • 输出结果:
    其他
    

case…esac 形式

类似于 C/C++ 中的 switch 语句。

  • 命令格式:
    case $变量名称 in
    值1)
        语句1
        语句2
        ...
        ;; # 类似于C/C++中的break
    值2)
        语句1
        语句2
        ...
        ;;
    *) # 类似于C/C++中的default
        语句1
        语句2
        ...
        ;;
    esac
    
  • 示例:
    a=4
    
    case $a in
    1)
        echo ${a}等于1
        ;;
    2)
        echo ${a}等于2
        ;;
    3)
        echo ${a}等于3
        ;;
    *)
        echo 其他
        ;;
    esac
    
  • 输出结果:
    其他
    

循环语句

for…in…do…done

  • 命令格式:
    for var in val1 val2 val3; do
        语句1
        语句2
        ...
    done
    
  • 示例 1,输出 a2cc,每个元素一行:
    for i in a 2 cc; do
        echo $i
    done
    
  • 示例 2,输出当前路径下的所有文件名,每个文件名一行:
    for file in $(ls); do
        echo $file
    done
    
  • 示例 3,输出1-10:
    for i in $(seq 1 10); do
        echo $i
    done
    
  • 示例 4,使用 {1..10} 或者 {a..z}
    for i in {a..z}; do
        echo $i
    done
    

for ((…;…;…)) do…done

  • 命令格式:
    for ((expression; condition; expression)); do
        语句1
        语句2
    done
    
  • 示例,输出1-10,每个数占一行:
    for ((i = 1; i <= 10; i++)); do
        echo $i
    done
    

while…do…done 循环

  • 命令格式:
    while condition; do
        语句1
        语句2
        ...
    done
    
  • 示例,文件结束符为 Ctrl+d ,输入文件结束符后 read 指令返回 false 。
    	while read name
    	do
    	    echo $name
    	done
    

until…do…done 循环

当条件为真时结束。

  • 命令格式:
    until condition; do
        语句1
        语句2
        ...
    done
    
  • 示例,当用户输入 yes 或者 YES 时结束,否则一直等待读入。
    until [ "${word}" == "yes" ] || [ "${word}" == "YES" ]; do
        read -p "Please input yes/YES to stop this program: " word
    done
    

break 命令

跳出当前一层循环,注意与 C/C++ 不同的是:break 不能跳出 case 语句。

  • 示例:
    while read name
    do
        for ((i=1;i<=10;i++))
        do
            case $i in
                8)
                    break
                    ;;
                *)
                    echo $i
                    ;;
            esac
        done
    done
    
    该示例每读入非 EOF 的字符串,会输出一遍 1-7 。该程序可以输入 Ctrl+d 文件结束符来结束,也可以直接用 Ctrl+c 杀掉该进程。

continue 命令

跳出当前循环。
示例:

for ((i = 1; i <= 10; i++)); do
    if [ $(expr $i % 2) -eq 0 ]; then
        continue
    fi
    echo $i
done

该程序输出1-10中的所有奇数。

函数

bash 中的函数类似于 C/C++ 中的函数,但 return 的返回值与 C/C++ 不同,返回的是exit code ,取值为 0-255 ,0 表示正常结束。

如果想获取函数的输出结果,可以通过 echo 输出到 stdout 中,然后通过 $(function_name) 来获取 stdout 中的结果。

函数的 return 值可以通过 $? 来获取。

命令格式:

[function] func_name() {  # function关键字可以省略
    语句1
    语句2
    ...
}

不获取 return 值和 stdout 值

  • 示例:
    func() {
        echo abc
    }
    
    func
    
  • 输出结果:
    abc
    

获取 return 值和 stdout 值

不写 return 时,默认 return 0 。

  • 示例:
    func() {
        echo abc
        return 123
    }
    
    output=$(func)
    ret=$?
    
    echo "output = $output"
    echo "return = $ret"
    
  • 输出结果:
    output = abc
    return = 123
    

函数的输入参数

在函数内,$1 表示第一个输入参数,$2 表示第二个输入参数,依此类推。

注意:函数内的 $0 仍然是文件名,而不是函数名。

  • 示例:
    func() { # 递归计算 $1 + ($1 - 1) + ($1 - 2) + ... + 0
            word=""
            while [ "${word}" != 'y' ] && [ "${word}" != 'n' ]; do
                read -p "要进入func($1)函数吗?请输入y/n:" word
            done
    
            if [ "$word" == 'n' ]; then
                echo 0
                return 0
            fi
    
        if [ $1 -le 0 ]; then
            echo 0
            return 0
        fi
    
        echo $(expr $(func $(expr $1 - 1)) + $1)
    }
    
    echo $(func 10)
    
  • 输出结果:
    55
    

函数内的局部变量

可以在函数内定义局部变量,作用范围仅在当前函数内。可以在递归函数中定义局部变量。

命令格式:local 变量名=变量值

例如:

func() {
    local a=abc
    echo $a
}
func

echo $a

输出结果:

abc

第一行为函数内的 a 变量,第二行为函数外调用 a 变量,会发现此时该变量不存在。

exit 命令

exit 命令用来退出当前 shell 进程,并返回一个退出状态;使用 $? 可以接收这个退出状态。exit 命令可以接受一个整数值作为参数,代表退出状态。如果不指定,默认状态值是 0 。exit 退出状态只能是一个介于 0~255 之间的整数,其中只有 0 表示成功,其它值都表示失败。

文件重定向

每个进程默认打开 3 个文件描述符:

  • stdin 标准输入,从命令行读取数据,文件描述符为 0 。
  • stdout 标准输出,向命令行输出数据,文件描述符为 1 。
  • stderr 标准错误输出,向命令行输出数据,文件描述符为 2 。

可以用文件重定向将这三个文件重定向到其他文件中。

重定向命令

  • command > file:将 stdout 重定向到 file 中。
  • command < file:将 stdin 重定向到 file 中。
  • command >> file:将 stdout 以追加方式重定向到 file 中。
  • command n> file:将文件描述符 n 重定向到 file 中。
  • command n>> file:将文件描述符 n 以追加方式重定向到 file 中。
  • exec 1>&0:stdout 重定向到 stdin 。

输入和输出重定向

echo -e "Hello \c" > output.txt  # 将stdout重定向到output.txt中
echo "World" >> output.txt  # 将字符串追加到output.txt中

read str < output.txt  # 从output.txt中读取字符串

echo $str  # 输出结果:Hello World

同时重定向 stdin 和 stdout

创建 bash 脚本:

#! /bin/bash

read a
read b

echo $(expr "$a" + "$b")

创建 input.txt ,里面的内容为:

3
4

执行命令:

$ ./test.sh < input.txt > output.txt  # 从input.txt中读取内容,将输出写入output.txt中
$ cat output.txt  # 查看output.txt中的内容
7

引入外部脚本

类似于 C/C++ 中的 include 操作,bash 也可以引入其他文件中的代码。

语法格式:

. filename  # 注意点和文件名之间有一个空格

source filename

docker

ssh

ssh 登录

基本用法

远程登录服务器:

ssh user@hostname
  • user: 用户名
  • hostname: IP 地址或域名

第一次登录时会提示:

The authenticity of host '123.57.47.211 (123.57.47.211)' can't be established.
ECDSA key fingerprint is SHA256:iy237yysfCe013/l+kpDGfEG9xxHxm0dnxnAbJTPpG8.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

输入 yes ,然后回车即可。这样会将该服务器的信息记录在 ~/.ssh/known_hosts 文件中。然后输入密码即可登录到远程服务器中。

ssh 默认登录端口号为 22 。如果想登录某一特定端口可以用 -p 参数指定。

ssh user@hostname -p 22

配置文件

创建文件 ~/.ssh/config ,然后在文件中输入:

Host myserver1
    HostName IP地址或域名
    User 用户名

Host myserver2
    HostName IP地址或域名
    User 用户名

之后再使用服务器时,可以直接使用别名 myserver1myserver2

密钥登录

创建密钥:

ssh-keygen

然后一直回车即可。

执行结束后,~/.ssh/ 目录下会多两个文件:

  • id_rsa:私钥
  • id_rsa.pub:公钥

之后想免密码登录哪个服务器,就将公钥传给哪个服务器即可。

例如,想免密登录 myserver 服务器。则将公钥中的内容,复制到 myserver 中的 ~/.ssh/authorized_keys 文件里即可。

也可以使用如下命令添加公钥:

ssh-copy-id myserver

执行命令

命令格式:ssh user@hostname command

scp传文件

命令格式:

  • source 路径下的文件复制到 destination 中:scp source destination
  • 一次复制多个文件:scp source1 source2 destination
  • 复制文件夹:scp -r ~/tmp myserver:/home/
  • 指定服务器的端口号:scp -P 22 source1 source2 destination
    注意: scp-r-P等参数尽量加在 sourcedestination 之前。

git

git 基本概念

  • 工作区:仓库的目录。工作区是独立于各个分支的。
  • 暂存区:数据暂时存放的区域,类似于工作区写入版本库前的缓存区。暂存区是独立于各个分支的。
  • 版本库:存放所有已经提交到本地仓库的代码版本
  • 版本结构:树结构,树中每个节点代表一个代码版本。

git 常用命令

  • git config --global user.name xxx:设置全局用户名,信息记录在 ~/.gitconfig 文件中。
  • git config --global user.email xxx@xxx.com:设置全局邮箱地址,信息记录在 ~/.gitconfig 文件中。
  • git init:将当前目录配置成 git 仓库,信息记录在隐藏的.git文件夹中。
  • git add XX:将 XX 文件添加到暂存区。
  • git add .:将所有待加入暂存区的文件加入暂存区。
  • git rm --cached XX:将文件从仓库索引目录中删掉。
  • git commit -m "给自己看的备注信息":将暂存区的内容提交到当前分支。
  • git status:查看仓库状态。
  • git diff XX:查看 XX 文件相对于暂存区修改了哪些内容。
  • git log:查看当前分支的所有版本。
  • git reflog:查看 HEAD 指针的移动历史(包括被回滚的版本)。
  • git reset --hard HEAD^git reset --hard HEAD~:将代码库回滚到上一个版本。
  • git reset --hard HEAD^^:往上回滚两次,以此类推。
  • git reset --hard HEAD~100:往上回滚 100 个版本。
  • git reset --hard 版本号:回滚到某一特定版本。
  • git checkout -- XXgit restore XX:将 XX 文件尚未加入暂存区的修改全部撤销。
  • git remote add origin git@git.acwing.com:xxx/XXX.git:将本地仓库关联到远程仓库。
  • git push -u (第一次需要-u以后不需要):将当前分支推送到远程仓库。
  • git push origin branch_name:将本地的某个分支推送到远程仓库。
  • git clone git@git.acwing.com:xxx/XXX.git:将远程仓库 XXX 下载到当前目录下。
  • git checkout -b branch_name:创建并切换到 branch_name 这个分支。
  • git branch:查看所有分支和当前所处分支。
  • git checkout branch_name:切换到 branch_name 这个分支。
  • git merge branch_name:将分支 branch_name 合并到当前分支上。
  • git branch -d branch_name:删除本地仓库的 branch_name 分支。
  • git branch branch_name:创建新分支。
  • git push --set-upstream origin branch_name:设置本地的 branch_name 分支对应远程仓库的 branch_name 分支。
  • git push -d origin branch_name:删除远程仓库的 branch_name 分支。
  • git pull:将远程仓库的当前分支与本地仓库的当前分支合并。
  • git pull origin branch_name:将远程仓库的 branch_name 分支与本地仓库的当前分支合并。
  • git branch --set-upstream-to=origin/branch_name1 branch_name2:将远程的 branch_name1 分支与本地的 branch_name2 分支对应。
  • git checkout -t origin/branch_name:将远程的 branch_name 分支拉取到本地。
  • git stash:将工作区和暂存区中尚未提交的修改存入栈中。
  • git stash apply:将栈顶存储的修改恢复到当前分支,但不删除栈顶元素。
  • git stash drop:删除栈顶存储的修改。
  • git stash pop:将栈顶存储的修改恢复到当前分支,同时删除栈顶元素。
  • git stash list:查看栈抱歉,似乎在我的回答中遗漏了一部分内容。以下是完整的。
  • git config --global user.name xxx:设置全局用户名,信息记录在 ~/.gitconfig 文件中。
  • git config --global user.email xxx@xxx.com:设置全局邮箱地址,信息记录在 ~/.gitconfig 文件中。
  • git init:将当前目录配置成 git 仓库,信息记录在隐藏的 .git 文件夹中。
  • git add XX:将 XX 文件添加到暂存区。
  • git add .:将所有待加入暂存区的文件加入暂存区。
  • git rm --cached XX:将文件从仓库索引目录中删掉。
  • git commit -m "给自己看的备注信息":将暂存区的内容提交到当前分支。
  • git status:查看仓库状态。
  • git diff XX:查看 XX 文件相对于暂存区修改了哪些内容。
  • git log:查看当前分支的所有版本。
  • git reflog:查看HEAD指针的移动历史(包括被回滚的版本)。
  • git reset --hard HEAD^git reset --hard HEAD~:将代码库回滚到上一个版本。
  • git reset --hard HEAD^^:往上回滚两次,以此类推。
  • git reset --hard HEAD~100:往上回滚 100 个版本。
  • git reset --hard 版本号:回滚到某一特定版本。
  • git checkout -- XXgit restore XX:将 XX 文件尚未加入暂存区的修改全部撤销。
  • git remote add origin git@git.acwing.com:xxx/XXX.git:将本地仓库关联到远程仓库。
  • git push -u (第一次需要 -u 以后不需要):将当前分支推送到远程仓库。
  • git push origin branch_name:将本地的某个分支推送到远程仓库。
  • git clone git@git.acwing.com:xxx/XXX.git:将远程仓库 XXX 下载到当前目录下。
  • git checkout -b branch_name:创建并切换到 branch_name 这个分支。
  • git branch:查看所有分支和当前所处分支。
  • git checkout branch_name:切换到 branch_name 这个分支。
  • git merge branch_name:将分支 branch_name 合并到当前分支上。
  • git branch -d branch_name:删除本地仓库的 branch_name 分支。
  • git branch branch_name:创建新分支。
  • git push --set-upstream origin branch_name:设置本地的 branch_name 分支对应远程仓库的branch_name分支。
  • git push -d origin branch_name:删除远程仓库的 branch_name 分支。
  • git pull:将远程仓库的当前分支与本地仓库的当前分支合并。
  • git pull origin branch_name:将远程仓库的 branch_name 分支与本地仓库的当前分支合并。
  • git branch --set-upstream-to=origin/branch_name1 branch_name2:将远程的 branch_name1 分支与本地的 branch_name2 分支对应。
  • git checkout -t origin/branch_name:将远程的 branch_name 分支拉取到本地。
  • git stash:将工作区和暂存区中尚未提交的修改存入栈中。
  • git stash apply:将栈顶存储的修改恢复到当前分支,但不删除栈顶元素。
  • git stash drop:删除栈顶存储的修改。
  • git stash pop:将栈顶存储的修改恢复到当前分支,同时删除栈顶元素。
  • git stash list:查看栈中所有元素。

管道、环境变量与常用命令

管道

概念

管道类似于文件重定向,可以将前一个命令的 stdout 重定向到下一个命令的 stdin 。

要点

  • 管道命令仅处理 stdout ,会忽略 stderr 。
  • 管道右边的命令必须能接受 stdin 。
  • 多个管道命令可以串联。

与文件重定向的区别

  • 文件重定向左边为命令,右边为文件。
  • 管道左右两边均为命令,左边有 stdout ,右边有 stdin 。

举例

统计当前目录下所有 python 文件的总行数

find . -name '*.py' | xargs cat | wc -l

环境变量

概念

Linux系统中会用很多环境变量来记录配置信息。环境变量类似于全局变量,可以被各个进程访问到。我们可以通过修改环境变量来方便地修改系统配置。

查看

列出当前环境下的所有环境变量:

env  # 显示当前用户的变量
set  # 显示当前 shell 的变量,包括当前用户的变量;
export  # 显示当前导出成用户变量的 shell 变量

输出某个环境变量的值

例如环境变量 PATH 的值:

echo $PATH

修改

  • 环境变量的定义、修改、删除操作可以参考 shell 中对变量的操作。

  • 为了将对环境变量的修改应用到未来所有环境下,可以将修改命令放到 ~/.bashrc 文件中。修改完 ~/.bashrc 文件后,记得执行 source ~/.bashrc ,来将修改应用到当前的 bash 环境下。

  • 为何将修改命令放到~/.bashrc,就可以确保修改会影响未来所有的环境呢?

    • 每次启动 bash ,都会先执行 ~/.bashrc
    • 每次 ssh 登陆远程服务器,都会启动一个 bash 命令行给我们。
    • 每次 tmux 新开一个 pane ,都会启动一个 bash 命令行给我们。
    • 所以未来所有新开的环境都会加载我们修改的内容。

常见环境变量

  • HOME:用户的家目录。
  • PATH:可执行文件(命令)的存储路径。路径与路径之间用:分隔。当某个可执行文件同时出现在多个路径中时,会选择从左到右数第一个路径中的执行。下列所有存储路径的环境变量,均采用从左到右的优先顺序。
  • LD_LIBRARY_PATH:用于指定动态链接库(.so 文件)的路径,其内容是以冒号分隔的路径列表。
  • C_INCLUDE_PATH:C 语言的头文件路径,内容是以冒号分隔的路径列表。
  • CPLUS_INCLUDE_PATH:CPP 的头文件路径,内容是以冒号分隔的路径列表。
  • PYTHONPATH:Python 导入包的路径,内容是以冒号分隔的路径列表。
  • JAVA_HOME:jdk 的安装目录。
  • CLASSPATH:存放 Java 导入类的路径,内容是以冒号分隔的路径列表。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/883182.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RocketMQ、Dashboard部署以及安全设置

RocketMQ、dashboard部署以及安全设置 一、启动RocketMQ1.1 下载RocketMQ1.2 修改配置文件1.2.1 修改nameServer Jvm内存配置1.2.2 修改broker参数 1.3 启动1.3.1 启动NameServer1.3.2 启动Broker1.3.3 测试是否启动成功1.3.3.1 测试消息发送1.3.3.2 测试消息接收1.3.3.3 Java程…

SSM——用户、角色、权限操作

1. 数据库与表结构 1.1 用户表 1.1.1 用户表信息描述 users 1.1.2 sql语句 CREATE TABLE users( id varchar2(32) default SYS_GUID() PRIMARY KEY, email VARCHAR2(50) UNIQUE NOT NULL, username VARCHAR2(50), PASSWORD VARCHAR2(50), phoneNum VARCHAR2(20), STATUS INT…

Ceph入门到精通-Aws Iam(user,role,group,policy,resource)架构图和快速入门

-- Aws Iam(identity,user,role,group,policy,resource,)架构图和快速入门. 【官网】&#xff1a;Cloud Computing Services - Amazon Web Services (AWS) 应用场景 aws 云服务运维,devops过程中经常涉及各项服务&#xff0c;权限&#xff0c;角色的处理。 为了更好的使用各项…

C语言入门 Day_4 小数 字符和常量

目录 前言 1.浮点型 2.字符型 3.易错点​​​​​​​ 4.思维导图 前言 我们学习了C语言中用来表示整数的数据类型&#xff1a;整型&#xff08;int&#xff09;&#xff0c;今天我们会学习用来表示小数的数据类型&#xff1a;浮点型&#xff08;float&#xff09; 1.浮点型 …

tinymce动态生成

最近在做一个vue项目, 其中用到了富文本tinymce插件,界面上需要有多个编辑器, 界面如下: ![在这里插入图片描述](https://img-blog.csdnimg.cn/f029b487c799482d8d53c2c31e07ccad.png 这里点击添加按钮, 需要动态添加tinymce组件 页面的元素 // item是v-for循环中的对象 <…

【第三阶段】kotlin语言的split

const val INFO"kotlin,java,c,c#" fun main() {//list自动类型推断成listList<String>val listINFO.split(",")//直接输出list集合&#xff0c;不解构println("直接输出list的集合元素&#xff1a;$list")//类比c有解构&#xff0c;ktoli…

linux下的lld命令

Linux下的lld命令的主要作用&#xff1a;用来查看程式运行所需的共享库&#xff08;动态链接库&#xff09;,常用来解决程式因缺少某个库文件而不能运行的一些问题。 1、首先ldd不是一个可执行程序&#xff0c;而只是一个shell脚本 2、ldd 的使用 lld 可执行程序或者动态库…

一维离散动力系统计算的基本理论

离散动力系统计算的基本理论 离散动力系统的基本概念与基本定理 离散动力系统的定义 形如 的迭代系统称为一个一阶离散动力系统。其中一阶指显式的仅依赖前一项类似得&#xff0c;我们可以定义m-阶离散动力系统 和更高维度的动力系统 不动点 不动点 周期轨道 周期与不变集 …

Android 组件

TextView 文本框 用于显示文本的一个控件。文本的字体尺寸单位为 sp 。sp: scaled pixels(放大像素). 主要用于字体显示。 文本常用属性 属性名说明id为TextView设置一个组件id&#xff0c;根据id&#xff0c;我们可以在Java代码中通过 findViewById()的方法获取到该对象&…

2011-2021年数字普惠金融指数Bartik工具变量法(含原始数据和Bartik工具变量法代码)

2011-2021年数字普惠金融指数Bartik工具变量法&#xff08;含原始数据和Bartik工具变量法代码&#xff09; 1、时间&#xff1a;2011-2020&#xff08;省级、城市&#xff09;&#xff0c;2014-2020&#xff08;区县&#xff09; 2、原始数据来源&#xff1a;北大金融研究中心…

IDEA 中Tomcat源码环境搭建

一、从仓库中拉取源代码 配置仓库地址、项目目录&#xff1b;点击Clone按钮&#xff0c;从仓库中拉取代码 Tomcat源码对应的github地址&#xff1a; https://github.com/apache/tomcat.git 二、安装Ant插件 打开 File -> Setting -> Plugins 三、添加Build文件 &…

UI设计师个人工作总结范文

UI设计师个人工作总结范文篇一 感受到了领导们“海纳百川”的胸襟&#xff0c;感受到了作为广告人“不经历风雨&#xff0c;怎能见彩虹”的豪气&#xff0c;也体会到了重庆广告从业人员作为拓荒者的艰难和坚定(就目前国内广告业而言&#xff0c;我认为重庆广告业尚在发展阶段并…

云曦暑期学习第五周——2022美亚杯个人赛

I.案件详情 于2022年10月&#xff0c;有市民因接获伪冒快递公司的电邮&#xff0c;不慎地于匪徒架设的假网站提供了个人信用咭资料导致经济损失。警方追查下发现当中一名受骗市民男子李大輝 (TaiFai) 的信用卡曾经被匪徒在区内的商舖购物。 后来警方根据IP地址&#xff0c;锁定…

(二分查找) 剑指 Offer 53 - I. 在排序数组中查找数字 I ——【Leetcode每日一题】

❓剑指 Offer 53 - I. 在排序数组中查找数字 I 难度&#xff1a;简单 统计一个数字在排序数组中出现的次数。 示例 1: 输入: nums [5,7,7,8,8,10], target 8 输出: 2 示例 2: 输入: nums [5,7,7,8,8,10], target 6 输出: 0 提示&#xff1a; 0 < n u m s . l e n g …

【Go语言】go_session(超级详细)

目录 前言附件代码审计Index函数Admin函数Flask函数server.py问题 思路本地搭建环境admin绕过SaveUploadedFile方法payload 总结 前言 国赛初赛有一道题目go session&#xff0c;用go的Gin框架和pongo2模板引擎写的&#xff0c;是关于go的pongo2模板注入和flask的热加载&#…

ICLR2020 Query2Box:基于BOX嵌入的向量空间知识推理8.15

Query2Box&#xff1a;基于BOX嵌入的向量空间知识推理 摘要介绍 摘要 在大规模不完全知识图谱上回答复杂的逻辑查询是一项基础性但具有挑战性的任务。最近&#xff0c;一种解决这个问题的很有前途的方法是将KG实体和查询嵌入到向量空间中&#xff0c;这样回答查询的实体紧密嵌…

Azure创建可用性集

什么是可用性集 在Azure中&#xff0c;可用性集&#xff08;Availability Set&#xff09;是一种用于提高虚拟机&#xff08;VM&#xff09;可用性和可靠性的功能。它通过将虚拟机分布在不同的物理硬件和故障域中来提供高可用性。每个故障域都是一个独立的电力和网络故障区域&…

gitlab合并新项目和分支切换

一、新建项目 1、创建空白项目 2、先创建一个群组 3、编写群组信息 4、创建群组完成以后新建项目 ​​​​​​​ 二、将代码推送到gitlab 1、初始化 git init 2、关联gitlab地址 # 比如:http://192.168.139.128:7070/cloud/obwt_cloud.git git remote add origin <你…