expect、正则表达式、sed、cut
一、expect
expect
是一个用于自动化交互式任务的工具,它的使用通常需要编写expect
脚本,并为该脚本传递必要的参数。expect"
命令本身通常不需要太多的参数,但脚本需要为特定的交互任务提供所需的参数和命令。
以下是一些常见的 expect
脚本参数:
-
spawn 命令: 用于启动要自动化的交互式命令行程序。例如:
spawn ssh user@hostname
-
expect 命令: 用于设置脚本等待的预期输出。通常,你需要提供一个字符串或正则表达式,以匹配命令行程序的输出。例如:
expect "password:"
-
send 命令: 用于向命令行程序发送输入。它通常用于自动输入用户名、密码或其他数据。例如:
send "my_password\r"
-
interact 命令: 用于将控制权返回给用户,使脚本进入交互模式。这允许用户手动干预或与命令行程序进行交互。例如:
interact
-
timeout 命令: 用于设置等待的超时时间,以便在一定时间内检查是否满足预期条件。如果超过了指定的超时时间,脚本可以采取适当的操
expect { "password:" { send "my_password\r" } timeout { send_user "Timed out waiting for password prompt\n" exit 1 } }
-
exp_continue 命令: 用于在匹配到一个预期后继续等待下一个预期输出,而不是退出脚本。
expect { "Username:" { send "my_username\r" exp_continue } "Password:" { send "my_password\r" } }
-
expect_user 命令: 用于等待用户输入,而不需要匹配特定的文本。它通常与
interact
命令一起使用,以在用户干预时暂停脚本。expect_user { "continue" { send "yes\r" } "quit" { send "no\r" exit } } interact
-
set 命令: 用于设置变量,以便在脚本中存储数据。
set username "my_username"
-
exp_send_user 命令: 用于向标准输出发送信息,通常用于显示脚本中的提示或消息。
exp_send_user "Please enter your username: "
-
$argv:
$argv
是一个特殊的变量,用于在Expect脚本中获取命令行参数(即脚本被调用时传递给脚本的参数)。这与Shell脚本中的$1
、$2
等位置参数类似。在Expect脚本中,
$argv
包含了一个列表,其中包含了脚本被调用时传递的所有参数。$argv
的第一个元素(即$argv(0)
)是脚本本身的名称,后续元素是脚本的参数。以下是一个示例,演示了如何在Expect脚本中使用
$argv
:
#!/usr/bin/expect
# 打印脚本的名称
puts "Script name: $argv(0)"
# 打印所有的参数
puts "Total number of arguments: [llength $argv]"
puts "Arguments: $argv"
# 打印特定参数
puts "First argument: $argv(1)"
puts "Second argument: $argv(2)"
如果你将上述脚本保存为 my_script.exp
并执行它,例如:
./my_script.exp arg1 arg2 arg3
那么脚本将会输出:
./my_script.exp
Total number of arguments: 4
Arguments: ./my_script.exp arg1 arg2 arg3
First argument: arg1
Second argument: arg2
这些是 expect
脚本中最常见的命令和参数。expect
脚本的核心思想是根据程序的输出预期和所需的输入来编写自动化任务。在脚本中,你可以使用条件语句、循环和变量来控制流程,以便根据交互的情况采取不同的行动。
例:免密ssh登录服务器
1、文件名需要exp
结尾
[root@fishman-160 ~]# vim ssh.exp
2、epect
脚本
1 #!/usr/bin/expect
2 set username "root"
3 set password "123.com"
4 set ip_addr "192.168.52.130"
5 set timeout "30"
6 spawn ssh $username@$ip_addr
7
8 expect {
9 "yes/no" { send "yes\r";exp_continue }
10 "password" { send "$password\r" }
11 }
12
13 expect "#" #登录成功后会有#,以此来判断是否成功
3、登录成功
例:批量免密ssh登录服务器
1、创建文件,保存用户名和密码
[root@fishman-160 ~]# vim ip_pass.txt
1 192.168.52.130 123.com
2 192.168.52.130 123.com
3 192.168.52.130 123.com
4 192.168.52.130 123.com
5 192.168.52.130 123.com
2、编写expect
脚本
[root@fishman-160 ~]# vim ssh2.exp
1 #!/usr/bin/expect
2
3 set ip_addr [lindex $argv 0]
4 set passwd [lindex $argv 1]
5 set username "root"
6 set timeout 30
7 spawn ssh $username@$ip_addr
8
9 expect {
10 "yes/no" { send "yes\r";exp_continue }
11 "password" { send "$passwd\r" }
12 }
13
14 expect "#" {
15 send "echo 'Logged in successfully'\r"
16 }
~
3、编写批量执行expect
脚本的shell
脚本
[root@fishman-160 ~]# vim login.sh
1 #!/bin/bash
2 for ip in `awk '{print $1}' /root/ip_pass.txt`
3 do
4 pass=`grep $ip /root/ip_pass.txt|awk '{print $2}'`
5 /usr/bin/expect /root/ssh2.exp $ip $pass
6 done
说明:
在Tcl/Expect编程中,lindex
是用来访问列表(List)中的元素的命令。它的语法如下:
lindex list index
-
list
是一个列表,可以包含多个元素。 -
index
是你要访问的元素的索引,索引从0开始。
在上面的 Expect 脚本中,lindex $argv 0
的意思是从命令行参数中的列表 $argv
中获取第一个元素(索引为0的元素),也就是脚本被调用时传递的第一个参数。
例如,如果你执行以下命令:
./myscript.exp 192.168.1.100 mypassword
那么 lindex $argv 0
将返回字符串 "192.168.1.100"
,而 lindex $argv 1
将返回字符串 "mypassword"
。
所以,lindex
在这里用于从命令行参数中提取脚本需要的 IP 地址和密码。
二、正则表达式
1、概念
在Shell编程中,正则表达式是一种强大的模式匹配工具,用于在文本数据中搜索、匹配和处理特定模式的字符串。正则表达式通常用于以下情况:
-
搜索和匹配文本: 正则表达式可以用来搜索和匹配文本中的特定模式,例如查找所有包含特定单词的行。
-
字符串替换: 正则表达式可以用于替换文本中的匹配模式,将其替换为其他字符串。
-
输入验证: 正则表达式可以用于验证用户输入是否符合特定格式或模式,例如验证电子邮件地址、电话号码等。
-
文本提取: 可以使用正则表达式从文本中提取感兴趣的信息,例如从日志文件中提取日期、时间等信息。
在Shell中,常用的正则表达式工具包括:
-
grep:
grep
命令用于在文本中搜索匹配正则表达式的行,并将它们打印到标准输出。 -
sed:
sed
命令用于在文本中搜索匹配正则表达式的内容,并执行替换等操作。 -
awk:
awk
是一种强大的文本处理工具,它可以使用正则表达式来分割、处理和过滤文本。
下面是一些常用的正则表达式元字符和模式:
-
.
:匹配任何字符。 -
*
:匹配前一个字符零次或多次。 -
+
:匹配前一个字符一次或多次。 -
?
:匹配前一个字符零次或一次。 -
[]
:定义字符集,匹配其中任何一个字符。 -
()
:标记子表达式的开始和结束。 -
|
:用于指定多个模式的"或"关系。 -
^
:匹配行的开头。 -
$
:匹配行的结尾。
示例:
-
^abc
:匹配以 "abc" 开头的行。 -
abc$
:匹配以 "abc" 结尾的行。 -
[0-9]
:匹配任何一个数字。 -
.*
:匹配任何字符零次或多次。
在Shell中使用正则表达式时,通常需要将正则表达式包含在引号内,以防止特殊字符被Shell解释。例如:
grep "pattern" file.txt
2、组成
特别字符 | 描述 |
---|---|
$ | 匹配输入字符串的结尾位置。要匹配 $ 字符本身,请使用 $. |
( ) | 标记一个子表达式的开始和结束位置。要匹配这些字符,请使用 和和。 |
* | 匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 *。 |
+ | 匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 +。 |
. | 匹配除换行符 \n 之外的任何单字符。要匹配 . ,请使用 . |
[ ] | 标记一个中括号表达式的开始。要匹配 [,请使用 [。 |
? | 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 ?。 |
\ | 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, 'n' 匹配字符 'n'。'\n' 匹配换行符。序列 '' 匹配 "",而 '(' 则匹配 "("。 |
^ | 匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合。要匹配 ^ 字符本身,请使用 ^。 |
{ } | 标记限定符表达式的开始。要匹配 {,请使用 {。 |
| | 指明两项之间的一个选择。要匹配 |,请使用 |。 |
^ | 匹配输入字符串开始的位置。 |
$ | 匹配输入字符串结尾的位置。 |
非打印字符 | |
\n | 匹配一个换行符。 |
\r | 匹配一个回车符。 |
\t | 匹配一个制表符。 |
例:匹配ip
[root@fishman-160 ~]# grep -E "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" /root/ip_pass.txt
192.168.52.130 123.com
192.168.52.130 123.com
192.168.52.130 123.com
192.168.52.130 123.com
192.168.52.130 123.com
三、sed
流编辑器
1、概念
sed
(Stream Editor)是一个用于文本处理的流式编辑器工具,通常用于从输入文本中进行文本替换、删除、插入、截取和转换等操作。它允许你基于一组规则(正则表达式或字符匹配)对文本进行批量处理,而不需要手动编辑文件。
sed
常用于命令行环境,可以通过终端执行。以下是一些常见的用途:
-
文本替换: 你可以使用
sed
来查找文本中的特定字符串,并将其替换为其他字符串。例如,将文件中的所有 "apple" 替换为 "orange"。 -
删除行或字符: 你可以使用
sed
删除文本中的特定行或字符。例如,删除包含特定关键词的行。 -
插入和追加:
sed
允许你在文本中的特定位置插入文本或在行的末尾追加文本。 -
截取和提取: 你可以使用
sed
从文本中提取特定的部分,例如提取文件中的特定行数或特定列的内容。 -
转换:
sed
可以用于文本的大小写转换、编码转换等操作。
sed
使用基于正则表达式的模式匹配来定位文本中的目标,并根据提供的命令来执行操作。以下是一个简单的示例,将文件中的所有 "apple" 替换为 "orange":
sed 's/apple/orange/g' filename.txt
在上述示例中,s/apple/orange/g
是 sed
的命令,表示将所有匹配的 "apple" 替换为 "orange",g
表示全局替换。
sed
是一个强大的文本处理工具,可以通过组合多个命令和正则表达式来执行复杂的文本操作。它在自动化文本处理和批量编辑文件时非常有用。
2、参数
sed
命令的基本语法如下:
sed [选项] [脚本] [输入文件]
2.1、选项
-
-n
:抑制自动输出,默认情况下,sed
会自动输出处理后的文本,使用-n
可以禁止自动输出。示例:打印匹配行,但不输出非匹配行。
sed -n '/pattern/p' input.txt
-
-e
:允许执行多个sed
指令,可以一次性指定多个操作。示例:同时执行多个操作。
sed -e 's/apple/orange/g' -e 's/banana/grape/g' input.txt
-
-f
:使用指定的脚本文件来执行sed
操作。示例:使用脚本文件
script.sed
执行操作。sed -f script.sed input.txt
-
-i
:直接编辑文件内容,修改文件。示例:替换文件中的文本并保存修改。
sed -i 's/old_text/new_text/g' file.txt
-
-i.bak
:编辑文件内容的同时创建一个备份文件,备份文件的扩展名可以自定义。示例:替换文件内容并创建备份文件。
sed -i.bak 's/old_text/new_text/g' file.txt
-
-r
:使用扩展的正则表达式模式。示例:使用
-r
启用扩展正则表达式模式。sed -r 's/(pattern1|pattern2)/replacement/g' input.txt
2.2、常用命令
-
a\
:在当前行下面插入文件的内容。示例:在匹配行下面插入一行文本。
sed '/pattern/a\ Inserted line below the pattern' input.txt
-
i\
:在当前行上面插入文件的内容。示例:在匹配行上面插入一行文本。
sed '/pattern/i\ Inserted line above the pattern' input.txt
-
c\
:将选定的行改为新的指定文本。示例:替换匹配行的内容。
sed '/pattern/c\ Replaced line with this text' input.txt
-
p
:打印匹配的行。示例:打印包含 "error" 的行。
sed -n '/error/p' input.txt
-
d
:删除匹配的行。示例:删除包含 "delete" 的行。
sed '/delete/d' input.txt
-
r
:从文件中读取内容并插入到当前行之后。示例:在匹配行之后插入文件内容。
sed '/pattern/r file_to_insert.txt' input.txt
-
R
:从文件中读取内容并插入到当前行之后,但只插入一行。示例:在匹配行之后插入一行文件内容。
sed '/pattern/R file_to_insert.txt' input.txt
-
w
:将匹配的行另存为指定文件。示例:将匹配行保存到另一个文件。
sed -n '/pattern/w output.txt' input.txt
-
s
:查找并替换。示例:将文本中的 "apple" 替换为 "orange"。
sed 's/apple/orange/g' input.txt
-
y
:字符替换。示例:将所有小写字母替换为大写字母。
sed 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' input.txt
-
h
:拷贝模板块的内容到内存中的缓冲区。示例:将匹配行的内容复制到内存中的缓冲区。
sed '/pattern/h' input.txt
-
H
:追加模板块的内容到内存中的缓冲区。示例:追加匹配行的内容到内存中的缓冲区。
sed '/pattern/H' input.txt
-
g
:获取内存缓冲区的内容,并替代当前模板块中的文本。示例:用内存中的内容替代匹配行的文本。
sed '/pattern/{g}' input.txt
-
G
:获取内存缓冲区的内容,并追加到当前模板块文本的后面。示例:将内存中的内容追加到匹配行的后面。
sed '/pattern/{G}' input.txt
-
D
:删除行中第一个换行符之前的内容。示例:删除匹配行中的一部分文本。
sed '/pattern/{D}' input.txt
-
P
:打印行中第一个换行符之前的内容。示例:打印匹配行中的一部分文本。
sed '/pattern/{P}' input.txt
2.3、替换标记
-
数字标记: 指明新文本将替换第几处模式匹配的地方。
示例:将第一次出现的 "apple" 替换为 "orange"。
echo "apple apple apple" | sed 's/apple/orange/' # 输出:orange apple apple
示例:将第二次出现的 "apple" 替换为 "orange"。
echo "apple apple apple" | sed 's/apple/orange/2' # 输出:apple orange apple
-
g 标记: 表示新文本将会替换所有匹配的文本。
示例:将所有 "apple" 替换为 "orange"。
echo "apple apple apple" | sed 's/apple/orange/g' # 输出:orange orange orange
-
\1 标记: 子串匹配标记,用于引用模式中的捕获组。
示例:交换两个单词的位置。
echo "John Smith" | sed 's/\(John\) \(Smith\)/\2 \1/' # 输出:Smith John
-
& 标记: 用于表示匹配的文本,通常用来替换。
示例:将匹配的单词加上括号。
echo "apple orange banana" | sed 's/[a-z]*/(&)/g' # 输出:(apple) (orange) (banana)
3、sed脚本
以下是一个简单的 script.sed
示例,该脚本将执行以下操作:
-
替换所有的 "apple" 为 "orange"。
-
在每一行的开头添加 "# "。
-
删除包含 "banana" 的行。
script.sed
的内容:
# 替换apple为orange
s/apple/orange/g
# 在每一行的开头添加"# "
s/^/# /
# 删除包含banana的行
/banana/d
要使用这个 script.sed
脚本处理一个文件(比如 input.txt
),你可以在命令行中这样执行:
sed -f script.sed input.txt > output.txt
这条命令会读取 input.txt
,应用 script.sed
中的所有 sed
命令,然后将结果输出到 output.txt
。
请注意,由于第二个命令会在每一行的开头添加 "# ",这可能会影响到你想要执行的其他操作,特别是如果这些操作依赖于行的具体内容。例如,在上面的脚本中,如果 "banana" 是某行的第一个单词,添加 "# " 之后该行将不再以 "banana" 开头,因此删除操作将不会生效。为了避免这种情况,你可能需要重新考虑命令的顺序或使用更复杂的逻辑来处理文本。
四、cut
cut
命令是一个用于从文本文件中提取字段或列的实用工具。它通常用于处理以固定分隔符(如制表符或逗号)分隔的数据文件。以下是一些常见用法和示例:
基本语法:
cut [选项] 文件名
常用选项:
-
-c 字符范围
:指定要提取的字符范围。 -
-f 字段列表
:指定要提取的字段列表。 -
-d 分隔符
:指定字段分隔符,默认为制表符。
示例用法:
-
提取文件中的特定字符范围:
cut -c 1-5 file.txt
这个命令将从
file.txt
文件中提取每行的第1到第5个字符。 -
提取文件中的特定字段:
cut -f 1,3 -d ',' data.csv
这个命令将从以逗号分隔的
data.csv
文件中提取第1和第3个字段。 -
使用不同的字段分隔符:
cut -f 2 -d ':' /etc/passwd
这个命令将从
/etc/passwd
文件中提取用户的第2个字段,使用冒号作为字段分隔符。 -
按字段范围提取:
cut -c 1-3,7-10 file.txt
这个命令将从
file.txt
文件中提取每行的第1到第3个字符和第7到第10个字符。
cut
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤