目录

送你一道shell题

学习夜老师博客https://7r1umphk.github.io/post/qun-zhu-ti.html (opens new window),看到一道群主不知道什么时候发的题目,来学习一下

因为对shell的掌握非常浅显,详细理解下题目

# 题目解读

题目源码如下

PATH=/usr/bin
read INPUT < <(head -n1 | tr -d "[A-Za-z0-9/]")
eval "$INPUT"
1
2
3

解释:

  • 重置环境变量
  • 读取输入,读取第一行并删除掉字母数字和斜杠,储存在INPUT变量中
  • eval执行INPUT变量值

详细讲讲第二条命令

read INPUT < <(head -n1 | tr -d "[A-Za-z0-9/]")
1

分成三部分:

read INPUT 、<、 <(head -n1 | tr -d "[A-Za-z0-9/]")

优先级问题,shell会先解释执行第三部分的进程替换语法,执行括号内的命令,把整体结果存放在临时文件中

┌──(npc㉿kali)-[~]
└─$ head --help
用法:head [选项]... [文件]...
将每个 <文件> 的前 10 行输出到标准输出。

如果没有指定 <文件>,或者 <文件>"-",则从标准输入读取。
  -c, --bytes=[-]数字      显示每个文件的前 <数字> 字节内容;
  -n, --lines=[-]数字         显示每个文件的前 <数字> 行内容而非前 10 行内容;
1
2
3
4
5
6
7
8

head命令默认读取文件前10行,如果没有指定文件或文件为-,则从标准输入读取,即从键盘输入

所以这里head -n1 读取键盘输入第一行

# tr

┌──(npc㉿kali)-[~]
└─$ tr --help
用法:tr [选项]... 字符串1 [字符串2]
从标准输入中替换、缩减和/或删除字符,并将结果写到标准输出。
<字符串1><字符串2> 用于指定字符数组 <数组1><数组2>,这两个
<数组> 将控制程序的行为。

  -c, -C, --complement    使用 <数组1> 的补集
  -d, --delete            删除 <数组1> 中的字符,不进行替换
1
2
3
4
5
6
7
8
9

tr -d "[A-Za-z0-9/]" 删除输入中所有字母、数字和斜杠

# 进程替换

<()语法会创建一个匿名管道,把括号内命令的执行结果重定向到该管道中(临时文件/dev/fd/xx)

┌──(npc㉿kali)-[~]
└─$ echo <(ls)        
/proc/self/fd/11
                                                                                                                                                                                                                                           
┌──(npc㉿kali)-[~]
└─$ echo <(echo 'test')
/proc/self/fd/11
                                                                                                                                                                                                                                           
┌──(npc㉿kali)-[~]
└─$ cat <(echo 'test') 
test
1
2
3
4
5
6
7
8
9
10
11

# read

┌──(npc㉿kali)-[~]
└─$ tldr read

  - 读取键盘输入的数据赋值给变量:
    read 变量
1
2
3
4
5

那么read INPUT就是从键盘输入中读取内容,赋值给INPUT变量,后面存在一个重定向符号<,表示从文件中读取内容,作为前面read命令的输入来源

head/read这些从键盘输入的命令都可以接收重定向的内容

┌──(npc㉿kali)-[~/hackmyvm/test]
└─$ head -n1 < <(ls)          
1.sh
                                                                                                                                                                                                                                           
┌──(npc㉿kali)-[~/hackmyvm/test]
└─$ read aaa < <(ls)          
                                                                                                                                                                                                                                           
┌──(npc㉿kali)-[~/hackmyvm/test]
└─$ echo $aaa         
1.sh
1
2
3
4
5
6
7
8
9
10

# 题目思路

现在知道

  • 题目从键盘输入读取第一行
  • 删除掉字母数字和斜杠
  • 把结果赋值给INPUT变量
  • 执行INPUT变量内容

# 通配符

把命令写进文件,通过. 文件名的方式执行,利用通配符匹配到执行的文件

┌──(npc㉿kali)-[~/hackmyvm/test]
└─$ cat 1.sh 
PATH=/usr/bin
read INPUT < <(head -n1 | tr -d "[A-Za-z0-9/]")
eval "$INPUT"
                                          
┌──(npc㉿kali)-[~/hackmyvm/test]
└─$ which whoami
/usr/bin/whoami
                                                                                                                                                                                                                                           
┌──(npc㉿kali)-[~/hackmyvm/test]
└─$ echo 'whoami' > 1
                                                                                                                                                                                                                                           
┌──(npc㉿kali)-[~/hackmyvm/test]
└─$ chmod +x 1.sh 
                                                                                                                                                                                                                                           
┌──(npc㉿kali)-[~/hackmyvm/test]
└─$ chmod +x 1   
                                                                                                                                                                                                                                           
┌──(npc㉿kali)-[~/hackmyvm/test]
└─$ bash 1.sh
. ?
npc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# shell变量

在shell环境里,有一些变量会自动被赋值

这里将一个特殊的变量$@,这是一个位置参数变量,表示传递给脚本或函数的所有参数,我以前会利用这个命令绕过关键字过滤

在没有参数时,它的值为空字符串,放进命令里不影响解析

┌──(npc㉿kali)-[~/hackmyvm/test]
└─$ mkdir -p testdir              
                                                                                                                                                                                                                                           
┌──(npc㉿kali)-[~/hackmyvm/test]
└─$ e$@cho '1111' > te$@stdir/1.$@txt
                                                                                                                                                                                                                                           
┌──(npc㉿kali)-[~/hackmyvm/test]
└─$ c$@at tes$@tdir/1.t$@xt
1111
1
2
3
4
5
6
7
8
9

在脚本或者函数里,可以打印传来的位置参数

┌──(npc㉿kali)-[~/hackmyvm/test]
└─$ cat get-params.sh 
echo $0
echo $1
echo $2
echo $@
                                                                                                                                                                                                                                           
┌──(npc㉿kali)-[~/hackmyvm/test]
└─$ sh get-params.sh 1 2 3 4
get-params.sh
1
2
1 2 3 4
1
2
3
4
5
6
7
8
9
10
11
12
13

$0b变量表示脚本名称,$@表示所有参数

所以可以通过$@变量,构造命令

还有一个位置参数的变量$*,会把所有参数当成一个整体,空格隔开

echo $*;
1

最后一次更新于: 2025/11/03, 02:17:47