自动化脚本自动化执行_自动化,自动化,自动化!

本文介绍了如何使用Shell脚本自动化UNIX系统中的任务,从简单的文件同步到复杂的命令行工具。通过示例脚本,展示了如何编写和利用Shell脚本进行任务自动化,包括参数处理、条件控制和命令行工具的集成。文章强调了脚本在简化重复工作和提高效率方面的作用。
摘要由CSDN通过智能技术生成

如果您在长时间工作的UNIX®用户的肩膀上凝视着他或她,那么您可能会对命令行中低调的奇怪咒语着迷。 如果您已经阅读了Speaking UNIX系列中的任何以前的文章(请参阅参考资料 ),则至少输入了一些神秘的符文-例如波浪号(〜),竖线(|),变量和重定向( <> )-看起来很熟悉。 您可能还会识别某些UNIX命令名称和组合,或者意识到何时将别名用作巫师的速记。

但是,其他命令行选项可能会让您难以理解,因为经验丰富的UNIX用户通常会以外壳程序脚本的形式聚集大量的小型,高度专业化的咒语,以简化或自动执行经常重复的任务。 Shell脚本可以使工作机械化,而不是键入和重新键入(可能)复杂的一系列命令来完成琐事。

在Speaking UNIX系列的第6部分(请参阅参考资料 )中,您将学习如何编写Shell脚本和更多命令行技巧。

本,只有一个词:“自动化”

一些Shell脚本运行完全相同的命令,一次又一次处理相同的文件集。 例如,一个Z shell脚本将您的主目录的全部内容传播到三台远程计算机,就像清单1一样简单。

清单1.一个简单的shell脚本可以在许多远程机器之间同步您的主目录
#! /bin/zsh

for each machine (groucho chico harpo)
    rsync -e ssh --times --perms --recursive --delete $HOME $machine:
end

要将清单1用作shell脚本,请将上面的内容保存到一个文件(例如simpleprop.zsh)中,然后运行chmod +x simpleprop.zsh使该文件可执行。 您可以通过键入./simpleprop.zsh来运行脚本。

如果您想了解Z shell如何扩展每个命令,请将-x选项添加到#!的末尾#! 脚本的(八度感叹号对通常称为shuh-bang )行,如下所示:

#! /bin/zsh -x

对于每台计算机grouchochicoharpo ,脚本都会运行rsync命令,将$HOME替换$HOME您的主目录(例如,/ home / joe),并将$machine替换为计算机名。

清单1所示 ,变量和脚本控制结构(例如循环)使脚本更易于编写和维护。 如果您要在池中添加第四台计算机(例如zeppo) ,只需将其添加到列表中即可。 如果必须更改rsync命令(例如,要添加另一个选项),则只需要编辑一个实例。 与传统编程一样,您也应努力避免在Shell脚本中进行剪切和粘贴。

提出一个很好的论据

其他外壳程序脚本需要参数或动态列表(文件,目录,计算机名称)进行处理。 作为示例,请考虑清单2 ,它是上一个示例的变体,它允许您使用命令行来命名要与之同步的计算机。

清单2.清单1的变体,使您可以命名要处理的计算机
#! /bin/zsh

for each machine
    rsync -e ssh --times --perms --recursive --delete $HOME $machine:
end

假设您将清单2保存在名为synch.zsh的文件中,则将脚本称为zsh synch.zsh moe larry curly调用以将主目录复制到计算机moe,larry和curl。

foreach行上缺少的列表不是错字:如果省略列表,则foreach结构将处理命令行中给出的参数列表。 命令行参数也称为位置参数,因为参数在命令行上的位置通常在语义上很重要。

例如, 清单2可以利用位置参数的存在或不存在来提供有用的用法消息(如果您未指定任何参数)。 增强的脚本如清单3所示。

清单3.如果没有提供参数,许多脚本会提供有用的消息
#! /bin/zsh

if [[ -z $1 || $1 == "--help" ]] 
then
    echo "usage: $0 machine [machine ...]
fi

foreach machine
    rsync -e ssh --times --perms --recursive --delete $HOME $machine:
end

命令行上每个以空格分隔的字符串都将成为一个位置参数,包括要调用的脚本的名称。 因此,命令synch.zsh仅具有一个位置参数$0synch.zsh --help命令有两个: $0$1 ,其中$1是字符串--help

因此, 清单3表示:“如果第一个位置参数为空( -z运算符测试一个空字符串),或者(如果由||表示)第一个参数等于'--help',则打印用法消息”。 (如果您开始编写脚本,请考虑在每个脚本中提供一个使用情况消息作为提示。它会提醒其他人-甚至您,如果您忘记了-都将如何使用该脚本。)

短语[[ -z $1 || $1 == "--help" ]] [[ -z $1 || $1 == "--help" ]]if语句的条件 ,但是您也可以使用与命令相同的条件,并将其与其他命令组合以控制脚本中的流程。 看一下清单4 。 它枚举$PATH所有可执行命令,并结合使用条件和其他命令来执行适当的工作。

清单4.在$ PATH中列出命令
#! /bin/zsh

directories=(`echo $PATH | column -s ':' -t`) 

for directory in $directories
do
  [[ -d $directory ]] || continue
  
  pushd "$directory"
  
  for file in *
  do
      [[ -x $file && ! -d $file ]] || continue
      echo $file
  done
  
  popd
done | sort | uniq

脚本中有很多事情要做,所以让我们将其分解为几部分:

  1. 脚本的第一行实际内容directories=(`echo $PATH | column -s ':' -t`) -创建一个命名目录数组。 您可以在zsh通过在参数周围加上括号来创建一个数组,如directories=( ... ) 。 在这种情况下,数组的元素是通过在每个冒号( column -s ':' )处拆分$PATH来生成的,以产生以空格分隔的目录列表( column-t参数)。
  2. 对于列表中的每个目录,脚本都会尝试枚举目录中的可执行文件。 步骤3至6描述了该过程。
  3. [[ -d $directory ]] || continue [[ -d $directory ]] || continue行是所谓short-circuiting命令的示例。 short-circuiting命令“一旦”其逻辑条件产生确定的结果就终止。

    例如, [[ -d $directory ]] || continue [[ -d $directory ]] || continue短语使用逻辑OR( || )-当且仅当第一个命令失败时,它执行第一个命令并执行第二个命令。 因此,如果$directory的条目存在并且是目录( -d运算符),则测试成功,评估结束,并且跳过当前元素处理的continue命令将永远不会执行。

    但是,如果第一个测试失败,则执行逻辑或continue的下一个条件。 ( continue总是成功的,因此它通常出现在short-circuiting命令的最后。)

    基于逻辑与( &&Short-circuiting执行第一个命令,然后(且仅当第一个命令成功时)才执行第二个命令。

  4. pushd和随附的popd分别用于在处理之前更改为新目录和在处理之后更改为先前目录。 使用目录堆栈是一种很好的脚本编写技术,可以保持您在文件系统中的位置。
  5. 内部的for循环枚举当前工作目录中的所有文件(通配符* (星号)匹配所有内容),然后测试每个条目是否为文件。 该行[[ -x $file && ! -d $file ]] || continue [[ -x $file && ! -d $file ]] || continue [[ -x $file && ! -d $file ]] || continue说:“如果$file存在且可执行并且不是目录,则对其进行处理;否则, continue 。”
  6. 最后,如果所有以前的条件都满足,则文件名将显示为echo
  7. 您是否抓住了脚本的最后一行? 您可以将大多数控制结构的输出发送到另一个UNIX命令-毕竟,shell将控制结构视为命令。 因此,整个脚本的输出通过sort管道传输,然后通过uniq管道生成$PATH找到的唯一命令的字母顺序列表。

如果将清单4保存到名为listcmds.zsh的可执行文件,则输出可能如下所示:

$ ./listcmds.zsh
[
a2p
ab
ac
accept
accton
aclocal

short-circuiting命令在脚本中非常有用。 它将条件和操作合二为一。 而且,由于每个UNIX命令都返回反映成功或失败的状态代码,因此您可以将任何命令都用作conditional命令,而不仅仅是测试操作员。 按照约定,UNIX命令成功返回零(0),失败则返回非零,其中非零值反映发生的错误的种类。

例如,如果行[[ -d $directory ]] || continue可以从清单4中删除pushdpopd [[ -d $directory ]] || continue被替换为cd $directory || continue cd $directory || continue 。 如果cd命令成功,它将返回0,并且逻辑或的评估可以立即结束。 但是,如果cd失败,它将返回非零值,评估继续进行并continue执行。

不要删除。 存档!

现代UNIX shell( bashkshzsh )提供了许多控制结构和操作来创建复杂的脚本。 因为您可以调用所有UNIX命令来将数据从一种形式转换为另一种形式,所以Shell脚本几乎与使用完整语言(例如C或Perl)进行编程一样丰富。

您可以使用脚本来机械化几乎任何个人或系统任务。 脚本可以监视,存档,更新,上载,下载和转换数据。 脚本可以是一行,也可以是一个庞大的子系统。 对于Shell脚本,没有任何事情太小或太大(几乎)。 确实,如果查看/etc/init.d目录,则会发现各种Shell脚本,这些脚本在每次启动计算机时都会启动服务。 如果创建一个非常有用的脚本,甚至可以将其部署为系统范围的实用程序。 只需将其放入用户$PATH上的目录中即可。

让我们创建一个实用程序来练习新发现的mojo。 脚本myrm替代了系统自身的rm。 myrm不会直接删除文件,而是将文件复制到存档中,对其进行唯一命名,以便以后可以找到它,然后删除原始文件。 myrm脚本功能强大但很简单,您可以添加许多功能。 您还可以将大量的unrm(“删除”)脚本作为辅助脚本来编写。 (您可以搜索Internet来找到各种实现。)

清单5中显示了myrm脚本。

清单5.一个简单的实用程序,用于在文件从文件系统中删除之前进行备份
#! /bin/zsh

backupdir=$HOME/.tomb
systemrm=/bin/rm

if [[ -z $1 || $1 == "--help" ]]
then
  exec $systemrm
fi

if [[ ! -d $backupdir ]]
then
  mkdir -m 0700 $backupdir || echo "$0: Cannot create $backupdir"; exit
fi

args$=$( getopt dfiPRrvw $* ) || exec $systemrm

count=0
flags = ""
foreach argument in $args
do
  case $argument in
    --) break;
        ;;

     *) flags="$flags $argument";
        (( count=$count + 1 ));
        ;;
  esac
done
shift $(( $count ))

for file
do
  [[ -e $file ]] || continue
  copyfile=$backupdir/$(basename $file).$(date "+%m.%d.%y.%H.%M.%S")
  /bin/cp -R $file $copyfile
done

exec $systemrm $=flags "$@"

您应该发现Shell脚本可读,尽管以前没有讨论过一些新东西。 让我们介绍一下这些内容,然后查看整个脚本。

  1. 当shell启动命令(例如cpls ,它将为该命令生成一个新进程,然后等待(sub)进程完成后再继续。 该exec命令也可以启动一个命令,但不是产生一个新的进程, exec “取代”当前进程的任务-那就是,外壳(或脚本)过程-以新的命令。 换句话说, exec重用相同的过程来启动新任务。 在脚本的上下文中, exec立即“终止”脚本并启动指定的任务。
  2. UNIX实用程序getopt扫描位置参数以查找您指定的命名参数。 在这里, dfiPRrvw列表查找-d-f-i-P-R-r-v-w 。 如果出现另一个选项,则getopt失败。 否则, getopt返回以特殊字符串--结尾的选项字符串。
  3. shift命令从左到右删除位置参数。 例如,如果命令行是myrm, -r -f -P file1 file2 file3 ,则shift 3将分别删除$0$1$2-r-f-Pfile1file2file3被重新编号为新的$0$1$2
  4. case语句的工作方式与传统编程语言中的类似:将其参数与列表中的每个模式进行比较; 找到匹配项时,将执行相应的代码。 就像在shell中一样, *匹配任何内容,并且如果找不到其他匹配项,则可以用作默认操作。
  5. 标记$@扩展为所有(其余)位置参数。
  6. zsh运算符$=在空白边界处分割单词。 $=当您有一个长字符串并且想要将字符串拆分为单独的参数时很有用。 例如,如果变量x包含字符串'-r -f'这是一个包含五个字符的单词- $=x成为两个单独的单词-r-f

有了这些说明,您现在应该可以完全剖析脚本了。 让我们看一下代码块:

  • 第一个块设置在整个脚本中使用的变量。
  • 下一个块应该看起来很熟悉:如果未提供任何参数,它将打印用法消息。 为什么exec真正的rm实用程序? 如果将此脚本命名为“ rm”并将其放在$PATH较早位置,则它可以充当/ bin / rm的代理。 脚本的错误选项还是/ bin / rm的错误选项,因此脚本使/ bin / rm提供使用情况消息。
  • 下一个块将创建备份目录(如果不存在)。 如果mkdir失败,则脚本会死于相应的错误消息。
  • 下一个块在位置参数列表中找到dash参数。 如果getopt成功,则$args具有选项列表。 如果getopt失败(在无法识别选项时发生),它将打印一条错误消息,并且脚本会退出并显示用法消息。
  • 以下块捕获了字符串中用于rm的所有选项。 当遇到特殊的getopt选项-- ,累积停止。 shift从参数列表中删除所有已处理的参数,保留要处理的文件和目录的列表。
  • for file开头的块是复制每个文件或目录的位置,以保存在您的个人“坟墓”中。 每个文件的目录都按原样( -R )复制到该坟墓中,并且在文件后缀当前日期和时间,以确保该副本是唯一的,并且不会破坏具有相同名称的先前存档条目。
  • 最后,使用传递给脚本的相同命令行选项删除文件或目录。

但是,如果您碰巧需要刚删除的文件或目录(偶然吗?),则可以在存档中查找原始副本!

继续自动化

使用UNIX的次数越多,创建脚本的可能性就越大。 脚本节省了重新键入复杂而冗长的命令序列所需的时间和精力,也防止了错误。 Web上充满了其他人为许多目的创建的有用脚本。 很快,您还将发布自己的咒语。


翻译自: https://www.ibm.com/developerworks/aix/library/au-speakingunix6.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值