脚本编程实用案例:加密、文件传输与新闻监控
1. 目录加密脚本
在UNIX系统中,
crypt
命令可对单个文件进行加密,但如果要同时加密多个文件,手动操作会很繁琐。下面的
cryptdir
脚本可以对指定目录下的所有文件进行加密或解密。
1.1 脚本功能概述
-
加密或解密
:根据脚本名称(
cryptdir或decryptdir)决定是加密还是解密操作。 - 密码验证 :加密时要求输入两次密码,避免因输入错误而导致文件加密失败。
-
避免重复加密
:使用
.crypt后缀来标识已加密文件,避免对已加密文件再次加密。
1.2 脚本代码
#!/usr/local/bin/expect --
# encrypt/decrypt an entire directory
# optional arg is dirname, else cwd
if {[llength $argv] > 0} {
cd $argv
}
# encrypt or decrypt?
set decrypt [regexp "decrypt" $argv0]
set timeout -1
stty -echo
send "Password:"
expect -re "(.*)\n"
send "\n"
set passwd $expect_out(1,string)
# wouldn't want to encrypt files with mistyped password!
if ! $decrypt {
send "Again:"
expect -re "(.*) \n"
send "\n"
if ! [string match $passwd $expect_out(1,string)] {
send_user "mistyped password?"
stty echo
exit
}
}
stty echo
log_user 0
foreach f [glob *] {
set strcmp [string compare .crypt [file extension $f]]
if $decrypt {
# skip files that don't end with ".crypt"
if 0!=$strcmp continue
spawn sh -c "exec crypt < $f > [file root $f]"
} else {
# skip files that already end with ".crypt"
if 0==$strcmp continue
spawn sh -c "exec crypt < $f > $f.crypt"
expect "key:"
send "$passwd\r"
expect
wait
exec rm -f $f
}
}
1.3 操作步骤
-
保存脚本
:将上述代码保存为
cryptdir或decryptdir。 -
赋予执行权限
:
chmod +x cryptdir decryptdir -
执行脚本
:
-
加密当前目录:
./cryptdir -
加密指定目录:
./cryptdir /path/to/directory -
解密当前目录:
./decryptdir -
解密指定目录:
./decryptdir /path/to/directory
-
加密当前目录:
2. 通过 Telnet 进行文件传输
传统的
ftp
程序在某些复杂网络环境下无法正常工作,下面的脚本可以在多种链接上进行文件传输,且不需要在远程端有副本。
2.1 脚本功能概述
- 交互式操作 :提示用户输入文件名和其他命令。
-
压缩和编码
:使用
compress和uuencode对文件进行压缩和编码,提高传输速度并解决二进制文件传输问题。 - 避免冲突 :使用进程 ID 来避免多个用户之间的冲突。
2.2 脚本代码
#!/usr/local/bin/expect --
if [info exists env(EXPECT_PROMPT)] {
set prompt $env(EXPECT_PROMPT)
} else {
set prompt "(%1#1\\$) $" ;# default prompt
}
set timeout -1
set verbose_flag 0
spawn -noecho $env(SHELL)
send_user "Once logged in, cd to directory to transfer\
to/from and press: --\n"
send_user "One moment ... \n"
interact -- cmd
proc cmd {} {
set CTRLZ \032
send_user "command (g,p,? for more): "
expect_user {
g get_main
p put_main
c chdir
v verbose
- {send "-"}
"\\?" {
send_user "?\n"
send_user "--g get file from remote system\n"
send_user "--p put file to remote system\n"
send_user "--c change/show directory on local system\n"
send_user "-- - send - to remote system\n"
send_user "--? this list\n"
send_user "--v verbose mode toggle\
(currently [verbose_status])\n"
send_user "--$CTRLZ suspend\n"
}
$CTRLZ {
stty -raw echo
exec kill -STOP [pid]
stty raw -echo
}
-re . {send_user "unknown command\n"}
send_user "resuming session ... \n"
}
}
proc verbose {} {
global verbose_flag
set verbose_flag [expr !$verbose_flag]
send_user "verbose [verbose_status]\r\n"
}
proc verbose_status {} {
global verbose_flag
if $verbose_flag {
return "on"
} else {
return "off"
}
}
proc send_verbose {msg} {
global verbose_flag
if $verbose_flag {
send_user $msg
}
}
proc chdir {} {
stty -raw echo
send_user "c\n"
send_user "current directory: [pwd], new directory: "
expect_user -re "(.*) \n" {
cd $expect_out(1,string)
stty raw -echo
}
}
proc get_main {} {
stty -raw echo
send_user "g\nget remote file \ [localfile] : "
expect_user {
-re "([A-Za-z0-9_.-]+) +([A-Za-z0-9_.-]+)\n" {
send_user "copying (remote) $expect_out(1,string) to\
(local) $expect_out(2,string)\n"
get $expect_out(1,string) $expect_out(2,string)
}
-re "([A-Za-z0-9_.-]+)\n" {
send_user "copying $expect_out(1,string)\n"
get $expect_out(1,string) $expect_out(1,string)
}
-re "\n" {
send_user "eh?\n"
stty raw -echo
}
}
}
proc put_main {} {
stty -raw echo
send_user "p\nput local file \ [remotefile] : "
expect_user {
-re "([A-Za-z0-9_.-]+) +([A-Za-z0-9_.-]+)\n" {
send_user "copying (local) $expect_out(1,string) to\
(remote) $expect_out(2,string)\n"
put $expect_out(1,string) $expect_out(2,string)
}
-re "([A-Za-z0-9_.-]+)\n" {
send_user "copying $expect_out(1,string)\n"
put $expect_out(1,string) $expect_out(1,string)
}
-re "\n" {
send_user "eh?\n"
stty raw -echo
}
}
}
proc get {infile outfile} {
global prompt verbose_flag
if (!$verbose_flag) {
log_user 0
}
send_verbose "disabling echo: "
send "stty -echo\r"
expect -re $prompt
send_verbose "remote pid is "
send "echo $$\r"
expect -re "(.*)\r\n.*$prompt"
set rpid $expect_out(1,string)
set pid [pid]
# pid is local pid, rpid is remote pid
set infile_main "/tmp/$rpid"
set infile_compressed "$infile_main.Z"
set infile_encoded "$infile_compressed.uu"
set outfile_main "/tmp/$pid"
set outfile_compressed "$outfile_main.Z"
set outfile_encoded "$outfile_compressed.uu"
set out [open $outfile_encoded w]
send_verbose "compressing\n"
send "compress -fc $infile > $infile_compressed\r"
expect -re $prompt
send_verbose "uuencoding\n"
send "uuencode $infile_compressed $outfile_compressed > \
$infile_encoded\r"
expect -re $prompt
send_verbose "copying\n"
send "cat $infile_encoded\r"
expect {
-re "end\r\n" {
puts $out "end"
close $out
}
-re "([^\r]*)\r\n" {
puts $out $expect_out(1,string)
send_verbose
exp_continue
}
}
if ($verbose_flag) {
send_user "\n"
}
log_user 1
expect -re $prompt ;# wait for prompt from cat
send_verbose "deleting temporary files\n"
send "rm -f $infile_compressed $infile_encoded\r"
expect -re $prompt
send_verbose "switching attention to local system\n\
uudecoding\n"
exec uudecode $outfile_encoded
send_verbose "uncompressing\n"
exec uncompress -f $outfile_compressed
send_verbose "renaming\n"
if [catch "exec cp $outfile_main $outfile" msg] {
send_user "could not move file in place, reason: $msg\n"
send_user "left as $outfile_main\n"
exec rm -f $outfile_encoded
} else {
exec rm -f $outfile_main $outfile_encoded
}
# restore echo and serendipitously reprompt
send "stty echo\r"
}
proc put {infile outfile} {
global prompt verbose_flag
if (!$verbose_flag) {
log_user 0
}
send_verbose "disabling echo: "
send "stty -echo\r"
expect -re $prompt
send_verbose "remote pid is "
send "echo $$\r"
expect -re "(.*)\r\n.*$prompt"
set rpid $expect_out(1,string)
set pid [pid]
# pid is local pid, rpid is remote pid
set infile_main "/tmp/$pid"
set infile_compressed "$infile_main.Z"
set infile_encoded "$infile_compressed.uu"
set outfile_main "/tmp/$rpid"
set outfile_compressed "$outfile_main.z"
set outfile_encoded "$outfile_compressed.uu"
set out [open $outfile_encoded w]
send_verbose "compressing\n"
exec compress -fc $infile > $infile_compressed
send_verbose "uuencoding\n"
exec uuencode $infile_compressed $outfile_compressed > \
$infile_encoded
send_verbose "copying\n"
send "cat > $outfile_encoded\r"
set fp [open $infile_encoded r]
while 1 {
if {-1 == [gets $fp buf]} break
send_verbose "."
send "$buf\r"
if ($verbose_flag) {
send_user "\n"
}
}
log_user 1
send "\004"
close $fp ;# eof
send_verbose "deleting temporary files\n"
exec rm -f $infile_compressed $infile_encoded
send_verbose "switching attention to remote system\n"
expect -re $prompt ;# wait for prompt from cat
send_verbose "uudecoding\n"
send "uudecode $outfile_encoded\r"
expect -re $prompt
send_verbose "uncompressing\n"
send "uncompress -f $outfile_compressed\r"
expect -re $prompt
send_verbose "renaming\n"
send "cp $outfile_main $outfile\r"
expect -re $prompt
send_verbose "deleting temporary files\n"
send "rm -f $outfile_main $outfile_encoded\r"
expect -re $prompt
# restore echo and serendipitously reprompt
send "stty echo\r"
}
2.3 操作步骤
-
保存脚本
:将上述代码保存为一个文件,例如
file_transfer。 -
赋予执行权限
:
chmod +x file_transfer -
执行脚本
:
./file_transfer -
连接远程系统
:使用
telnet或tip等外部程序连接到远程系统。 - 进入远程目录 :在远程系统中进入要进行文件传输的目录。
-
执行命令
:输入
--调用cmd过程,根据提示输入相应命令进行文件传输。
3. 未读新闻监控脚本 tknewsbiff
tknewsbiff
脚本可以监控 Usenet 新闻,当有未读新闻时,会播放音频或执行其他操作。
3.1 脚本功能概述
- 可定制性 :用户可以通过添加额外的 Tcl 命令来自定义脚本行为。
- 新闻监控 :定期检查新闻服务器,显示有未读新闻的新闻组和未读文章数量。
- 用户交互 :提供简单的鼠标绑定,方便用户操作。
3.2 脚本代码
#!/usr/local/bin/expectk
proc unmapwindow {} {
global _window_open
switch [wm state .] {
iconic {
set _window_open 0
}
normal {
set _window_open 1
}
}
wm withdraw .
}
unmapwindow
# force window to be open when mapped for the first time
set _window_open 1
proc mapwindow {} {
global _window_open
if $_window_open {
wm deiconify .
} else {
wm iconify .
}
}
proc _abort {msg} {
global argv0
puts "$argv0: $msg"
exit 1
}
if [info exists env(DOTDIR)] {
set home $env(DOTDIR)
} else {
set home [glob -]
}
set delay 60
set width 27
set height 10
set _default_config_file $home/.tknewsbiff
set _config_file $_default_config_file
set default_server "news"
set server $_default_server
set server_timeout 60
log_user 0
listbox .list -yscroll ".scrollbar set" -font "*-m-*" -setgrid 1
scrollbar .scrollbar -command ".list yview" -relief raised
pack .scrollbar -side left -fill y
pack .list -side left -fill both -expand 1
while {[llength $argv]>0} {
set arg [lindex $argv 0]
if [file readable $arg] {
if 0== [string compare "active" [file tail $arg]] {
set active_file $arg
set argv [lrange $argv 1 end]
} else {
# must be a config file
set _config_file $arg
set argv [lrange $argv 1 end]
}
} elseif {[file readable $_config_file-$arg]} {
# maybe it's a hostname suffix for a newsrc file?
set _config_file $_default_config_file-$arg
set argv [lrange $argv 1 end]
} else {
# maybe just a hostname for a regular newsrc file?
set server $arg
set argv [lrange $argv 1 end]
}
}
proc _read_config_file {} {
global _config_file argv0 watch_list ignore_list
proc user {} {}
set watch_list {}
set ignore_list {}
if [file exists $_config_file] {
# uplevel allows user to set global variables
if [catch {uplevel source $_config_file} msg] {
_abort "error reading $_config_file\n$msg"
}
}
if [llength $watch_list]==0 {
watch *
}
}
proc watch {args} {
global watch_list
lappend watch_list $args
}
proc ignore {ng} {
global ignore_list
lappend ignore_list $ng
}
_read_config_file
# if user didn't set newsrc, try -/.newsrc-server
# if that fails, fall back to just plain -/.newsrc
if ![info exists newsrc] {
set newsrc $home/.newsrc-$server
if ![file readable $newsrc] {
set newsrc $home/.newsrc
if ![file readable $newsrc] {
_abort "cannot tell what newgroups you read - found\
neither $home/.newsrc-$server nor $home/.newsrc"
}
}
}
# initialize display
set min_reasonable_width 8
wm minsize . $min_reasonable_width 1
wm maxsize . 999 999
if {0 == [info exists active_file] &&
0 != [string compare $server $_default_server]} {
wm title . "news@$server"
wm iconname . "news@$server"
}
proc _read_newsrc {} {
global db newsrc
if [catch {set file [open $newsrc]} msg] {
_abort $msg
}
while {-1 != [gets $file buf]} {
if [regexp "!" $buf] continue
if [regexp "([^:]*):.*[-, ] ([0-9]+)" $buf dummy ng seen] {
set db($ng, seen) $seen
}
}
close $file
}
proc _read_active {} {
global db server active_list active_file
upvar #0 server_timeout timeout
set active_list {}
if [info exists active_file] {
spawn -open [open $active_file]
} else {
spawn telnet $server nntp
expect {
"20*\n" {
# should get 200 or 201
}
"NNTP server*\n" {
puts "tknewsbiff: unexpected response from server:"
puts "$expect_out(buffer) "
return 1
}
"unknown host" {
_unknown_host
}
timeout {
close
wait
return 1
}
eof {
# loadav too high probably
wait
return 1
}
}
exp_send "list\r"
# ignore echo of "list" command
expect "list\r\n"
# skip "Newsgroups in form" line
expect -re "215\[^\n]*\n"
expect -re "([^ ]*) 0*([^ ]+) [^\n]*\n" {
set ng $expect_out(1,string)
set hi $expect_out(2,string)
lappend active_list $ng
set db($ng,hi) $hi
exp_continue
}
" . \r\n" {
close
wait
return 0
}
}
}
proc _unknown_host {} {
global server _default_server
if 0==[string compare $_default_server $server] {
puts "tknewsbiff: default server <$server> is not known"
} else {
puts "tknewsbiff: server <$server> is not known"
}
puts "Give tknewsbiff an argument - either the name\
of your news server or active file.
I.e.,
tknewsbiff news.nist.gov
tknewsbiff /usr/news/lib/active
\n\
If you have a correctly defined configuration file\
(.tknewsbiff), an argument is not required.
See the\
man page for more info."
exit 1
}
proc _update_ngs {} {
global watch_list active_list newsgroup
foreach watch $watch_list {
set threshold 1
set display "display"
set new {}
set ngpat [lindex $watch 0]
set watch [lrange $watch 1 end]
while {[llength $watch] > 0} {
switch -- [lindex $watch 0] {
-threshold {
set threshold [lindex $watch 1]
set watch [lrange $watch 2 end]
}
-display {
set display [lindex $watch 1]
set watch [lrange $watch 2 end]
}
-new {
set new [lindex $watch 1]
set watch [lrange $watch 2 end]
}
default {
_abort "watch: expecting -threshold, -display or\
-new but found: [lindex $watch 0]"
}
}
}
foreach ng $active_list {
if [string match $ngpat $ng] {
if [_isgood $ng $threshold] {
if [llength $display] {
set newsgroup $ng
uplevel $display
}
if [_isnew $ng] {
if [llength $new] {
set newsgroup $ng
uplevel $new
}
}
}
}
}
}
}
proc _isgood {ng threshold} {
global db seen_list ignore_list
# skip if we don't subscribe to it
if ! [info exists db($ng,seen)] {return 0}
# skip if the threshold isn't exceeded
if {$db($ng,hi) - $db($ng,seen) < $threshold} {
return 0
}
# skip if it matches an ignore command
foreach igpat $ignore_list {
if [string match $igpat $ng] {return 0}
}
# skip if we've seen it before
if [lsearch -exact $seen_list $ng] !=-1 {return 0}
# passed all tests, so remember that we've seen it
lappend seen_list $ng
return 1
}
proc _isnew {ng} {
global previous_seen_list
if [lsearch -exact $previous_seen_list $ng]==-1 {
return 1
} else {
return 0
}
}
proc display {} {
global display_list newsgroup
lappend display_list $newsgroup
}
proc _update_window {} {
global server display_list height width
global min_reasonable_width
if {0 == [llength $display_list]} {
unmapwindow
return
}
# make height correspond to length of display_list or
# user's requested max height, whichever is smaller
if {[llength $display_list] < $height} {
set current_height [llength $display_list]
} else {
set current_height $height
}
# force reasonable min width
if {$width < $min_reasonable_width} {
set width $min_reasonable_width
}
wm geometry . "${width}x$current_height"
wm maxsize . 999 [llength $display_list]
if [string compare [wm state .] "withdrawn"]==0 {
mapwindow
}
_display_ngs $width
}
proc _display_ngs {width} {
global db display_list
set str_width [expr $width-7]
.list delete 0 end
foreach ng $display_list {
.list insert end [
format "%-$str_width.${str_width}s %5d" \
$ng [expr $db($ng,hi) - $db($ng,seen)]
]
}
}
bind .list <1> help
bind .list <2> update-now
bind .list <3> unmapwindow
bind .list <Configure> {
scan [wm geometry .] "%dx%d" w h
_display_ngs $w
}
spawn cat -u; set _cat_spawn_id $spawn_id
set _update_flag 0
proc _sleep {timeout} {
global _cat_spawn_id _update_flag
# restore to idle cursor
.list config -cursor ""; update
# sleep for a little while, subject to click from
# "update" button
expect -i $_cat_spawn_id -re "....";# two crlfs
# change to busy cursor
.list config -cursor watch; update
}
proc update-now {} {
global _update_flag _cat_spawn_id
if $_update_flag return
set _update_flag 1
}
set previous_seen_list {}
set seen_list {}
proc _init_ngs {} {
global display_list db
global seen_list previous_seen_list
set display_list {}
set seen_list {}
catch {unset db}
}
for {} 1 {_sleep $delay} {
_init_ngs
_read_newsrc
if [_read_active] continue
_read_config_file
_update_ngs
user
_update_window
}
2.4 操作步骤
-
保存脚本
:将上述代码保存为
tknewsbiff。 -
赋予执行权限
:
chmod +x tknewsbiff -
创建配置文件
:在用户主目录下创建
.tknewsbiff文件,添加自定义配置,例如:
set server news.nist.gov
set delay 120
set server_timeout 60
set height 10
watch comp.unix.*
watch *.sources.*
watch dc.dining
ignore *.d
-
执行脚本
:
./tknewsbiff
2.5 鼠标绑定说明
| 鼠标按键 | 功能 |
|---|---|
| 左键 | 弹出帮助窗口 |
| 中键 | 立即检查新的未读新闻 |
| 右键 | 隐藏窗口直到下一个更新周期 |
| 窗口调整大小 | 重新绘制窗口 |
2.6 mermaid 流程图
graph TD;
A[开始] --> B[初始化窗口和变量];
B --> C[读取配置文件];
C --> D[读取 newsrc 文件];
D --> E[检查新闻组文章数量];
E --> F[更新新闻组信息];
F --> G[执行用户自定义操作];
G --> H[更新窗口显示];
H --> I[休眠];
I --> D;
以上就是三个实用脚本的详细介绍和操作步骤,希望能帮助你更好地完成目录加密、文件传输和新闻监控等任务。
4. 脚本技术细节分析
4.1 目录加密脚本技术点
-
密码验证
:在加密过程中,为避免因输入错误的密码而导致文件加密失败,脚本要求用户输入两次密码,并使用
string match函数进行比较。若两次输入不一致,脚本将提示错误并退出。
if ! $decrypt {
send "Again:"
expect -re "(.*) \n"
send "\n"
if ! [string match $passwd $expect_out(1,string)] {
send_user "mistyped password?"
stty echo
exit
}
}
-
避免重复加密
:脚本使用
.crypt后缀来标识已加密文件。在遍历文件列表时,通过string compare函数比较文件扩展名,跳过已加密或无需解密的文件。
foreach f [glob *] {
set strcmp [string compare .crypt [file extension $f]]
if $decrypt {
# skip files that don't end with ".crypt"
if 0!=$strcmp continue
spawn sh -c "exec crypt < $f > [file root $f]"
} else {
# skip files that already end with ".crypt"
if 0==$strcmp continue
spawn sh -c "exec crypt < $f > $f.crypt"
expect "key:"
send "$passwd\r"
expect
wait
exec rm -f $f
}
}
4.2 文件传输脚本技术点
-
压缩和编码
:为提高传输速度和解决二进制文件传输问题,脚本使用
compress和uuencode对文件进行压缩和编码。在get和put过程中,分别对文件进行相应处理。
# get 过程中的压缩和编码
send_verbose "compressing\n"
send "compress -fc $infile > $infile_compressed\r"
expect -re $prompt
send_verbose "uuencoding\n"
send "uuencode $infile_compressed $outfile_compressed > \
$infile_encoded\r"
expect -re $prompt
# put 过程中的压缩和编码
send_verbose "compressing\n"
exec compress -fc $infile > $infile_compressed
send_verbose "uuencoding\n"
exec uuencode $infile_compressed $outfile_compressed > \
$infile_encoded
-
避免冲突
:使用进程 ID(
pid)来避免多个用户之间的冲突。在本地和远程系统中,分别使用不同的进程 ID 来命名临时文件。
set pid [pid]
# pid is local pid, rpid is remote pid
set infile_main "/tmp/$rpid"
set infile_compressed "$infile_main.Z"
set infile_encoded "$infile_compressed.uu"
set outfile_main "/tmp/$pid"
set outfile_compressed "$outfile_main.Z"
set outfile_encoded "$outfile_compressed.uu"
4.3 tknewsbiff 脚本技术点
-
可定制性
:用户可以通过在配置文件中添加额外的 Tcl 命令来自定义脚本行为。脚本使用
uplevel source函数来执行配置文件中的代码,允许用户设置全局变量和调用其他过程。
proc _read_config_file {} {
global _config_file argv0 watch_list ignore_list
proc user {} {}
set watch_list {}
set ignore_list {}
if [file exists $_config_file] {
# uplevel allows user to set global variables
if [catch {uplevel source $_config_file} msg] {
_abort "error reading $_config_file\n$msg"
}
}
if [llength $watch_list]==0 {
watch *
}
}
-
新闻监控和更新
:脚本定期检查新闻服务器,通过
_read_newsrc和_read_active过程读取用户的新闻源文件和新闻组文章数量。然后,使用_update_ngs过程更新新闻组信息,并根据用户配置执行相应操作。
for {} 1 {_sleep $delay} {
_init_ngs
_read_newsrc
if [_read_active] continue
_read_config_file
_update_ngs
user
_update_window
}
5. 脚本优化建议
5.1 目录加密脚本优化
-
错误处理
:在执行
crypt命令时,添加错误处理机制,捕获可能的错误并输出详细的错误信息。 -
并行处理
:对于大量文件的加密或解密操作,可以考虑使用并行处理来提高效率。例如,使用
exec命令在后台执行多个crypt进程。
5.2 文件传输脚本优化
-
工具检查
:在脚本开始时,检查远程主机是否支持
rz/sz或gzip等工具,并优先使用这些工具进行文件传输。 - 减少临时文件 :利用压缩程序可以读写管道的特性,减少临时文件的使用,避免磁盘空间的浪费。
5.3 tknewsbiff 脚本优化
- 性能优化 :减少不必要的文件读取和网络请求,例如缓存新闻组信息,避免重复检查。
- 用户体验优化 :添加更多的用户交互功能,如自定义声音提示、消息通知等。
6. 总结
本文介绍了三个实用脚本:目录加密脚本、文件传输脚本和未读新闻监控脚本
tknewsbiff
。这些脚本具有不同的功能和特点,通过详细的代码分析和操作步骤说明,帮助读者理解和使用这些脚本。同时,还提供了脚本的技术细节分析和优化建议,希望能为读者在实际应用中提供参考。
6.1 脚本功能总结
| 脚本名称 | 功能 |
|---|---|
| 目录加密脚本 | 对指定目录下的所有文件进行加密或解密 |
| 文件传输脚本 | 在多种链接上进行文件传输,支持交互式操作 |
| tknewsbiff 脚本 | 监控 Usenet 新闻,当有未读新闻时执行相应操作 |
6.2 mermaid 流程图
graph LR;
A[目录加密脚本] --> B[文件传输脚本];
B --> C[tknewsbiff 脚本];
C --> D[优化建议];
D --> A;
通过学习和使用这些脚本,读者可以提高工作效率,实现自动化任务,同时也可以根据自己的需求对脚本进行定制和优化。
超级会员免费看

被折叠的 条评论
为什么被折叠?



