⑴ 如何将一shell脚本中的每一步命令执行结果输出到指定日志文件中
使用tee命令:
sh portal/main.sh |tee log.txt
获耐亩轿昌肆取耐携脚本父类路径
cmddir="`dirname $0`"
⑵ 怎样让BAT文件运行时打印出的内容既能显示在DOS窗口,又能记录到日志
1.“wevtutil el ” //列出日志名称
”wevtutil gl 日志名称“ //获取日志配置信息。罩肆衫
2.Windows 事件命令行实用程序。
用于检索有关事件日志和发布者的信息,
安装和卸载事件清单,运行查询以及导出、存档和清除日志。
用法:
你可以使用短(如 ep /uni)或长(如
enum-publishers /unicode)形式的命令和选项名称。
命令、选项和选项值不区分大小写。
变量均使用大写形式。
wevtutil COMMAND [ARGUMENT [ARGUMENT] ...] [/OPTION:VALUE [/OPT
命令:
el | enum-logs 列出日志名称。
gl | get-log 获取日志配置信息。
sl | set-log 修改日志配置。
ep | enum-publishers 列出事件发布者。
gp | get-publisher 获取发布者配置信息。
im | install-manifest 从清单中安装事件发布者和日志。
um | uninstall-manifest 从清单中卸载事件发布者和日志。
qe | query-events 从日志或日志文件中查询事件。
gli | get-log-info 获取日志状态信息。
epl | export-log 导出日志。
al | archive-log 存档导出的日志。
cl | clear-log 清除日志。
常用选项:
/{r | remote}:VALUE
如果指定,则在远程计算机上运行该命令。VALUE 是远程计算机名称。
/im 和 /um 选项不支持远程操作。
/{u | username}:VALUE
指定一个不同的用户以登录到远程计算机。
VALUE 是 domain\user 或 user 形式的用户名。只有在指定 /r 选项时
/{p | password}:VALUE
指定的用户密码。如果未指定,
或者 VALUE 为 "*",则会提物腔示用户输入密码。
只有在指定 /u 选项时才适用。
/{a | authentication}:[Default|Negotiate|Kerberos|NTLM]
用于连接到远程计算机的身份验证类型。默认值为雹吵 Negotiate。
/{uni | unicode}:[true|false]
使用 Unicode 显示输出。如果为 true,则使用 Unicode 显示输出。
⑶ shell脚本怎么生成运行日志
自己写的脚本调用的日志打印函数,供参考
在脚本开头的工作
定义日志文件LOGFILE
定义日志序列号文件_LOGSEQ
定义日志函数
log()
{
#检查是否存在日志文件,如果存在,则检查文件是否过大(20M)
#过大时,切换文件,并将目前的日志序列号保存在_LOGSEQ中。
if [ -f $LOGFILE ];then
LogFileLen=`ls -l ${LOGFILE} | awk '{print $5}'`
if [ $LogFileLen -gt 20971520 ]; then
if [ -f ${_LOGSEQ} ] ; then
_OrgSeq="`cat ${_LOGSEQ}`"
if [ $_OrgSeq -gt 98 ];then
LogFileSeq=0
else
LogFileSeq=`expr ${_OrgSeq} + 1`
fi
else
LogFileSeq=0
fi
echo "${LogFileSeq}" > ${_LOGSEQ}
mv $LOGFILE ${LOGFILE}.${LogFileSeq}
fi
fi
_LogInfo=$1
echo `date +20'%y-%m-%d %H:%M:%S'`" ${_LogInfo} " >> ${LOGFILE} 2>&1
}
需要打日志时调用log函数即可
⑷ 如何将一shell脚本中的每一步命令执行结果输出到指定日志文件中
$?获取毕李每一步执行的结袭数坦果,输出到拍桐日志中就是正常的写日志动作就行
echo "" > /var/log/你的log
或者rsyslog啥的,我记得有个函数,你用这个函数也行。
⑸ Linux 下Python 脚本编写的"奇技淫巧"
“ 生命完美的答案,无非走过没有遗憾 ---《天蓝》”
“如何能够解析脚本运行命令行选项(位于 sys.argv 中)”
argparse 模块可被用来解析命令行选项
常用来定义一个脚本的说明文档,一般我们写python脚本会通过 if..else 的方式来提供一个脚本说明文档,python不支持switch。所以很麻烦,其实,我们可以通过 argparse 来编写说明文档。
我们来看看怎么执行一个python脚本
对于熟悉Linux的小伙伴下面的文档在熟悉不过了,这个一个标准Linxu软件包的说明文档,文档中定义是软件包的说明
来看看这个脚本是如何编写的
为了解析命令行选项, 首先要创建一个 ArgumentParser 实例, 使用 add_argument() 方法声明你想要支持的选项。在每个 add-argument() 调用中:
dest 参数指定解析结果被指派给属性的名字。 metavar 参数被用来生成帮助信息。
action 参数 指定跟属性对应的处理逻辑,通常的 值为 store , 被用来存储 某个值 或将 多个参数值收集到一个列表中 。
nargs 参数收集 所有剩余的命令行参数到一个列表中。在本例中它被用来构造一个文件名列表
action='store_true' 根据参数是否存在来设置一个位置 Boolean 标志:
action='store' 参数接受一个单独值并将其存储为一个字符串
如果一个都没有,会提示缺少参数 -p/--pat
choices={'slow', 'fast'}, 参数说明接受一个值,但是会将其和可能的选择值做比较,以检测其合法性:
一旦参数选项被指定,你就可以执行 parser.parse() 方法了。它会处理 sys.argv 的值并返回一个结果实例。每个参数值会被设置成该实例中 add_argument() 方法的 dest 参数指定的属性值。
还很多种其他方法解析命令行选项。可以会手动地处理 sys.argv 或者使用 getopt 模块 。但是,如果你采用本节的方式,将会减少很多冗余代码,底层细节 argparse 模块 已经帮你处理好了。你可能还会碰到使用 optparse 库解析选项的代码。尽管 optparse 和 argparse 很像 ,但是后者更先进,因此在新的程序中你应该使用它。
“你写了个脚本,运行时需要一个密码。此脚本是交互式的,因此不能将密码在脚本中硬编码,而是需要弹出一个密码输入提示,让用户自己输入。”
Python 的 getpass 模块 正是你所需要的。你可以让你很轻松地弹出密码输入提示,并且不会在用户终端显示密码。
代码中 getpass.getuser() 不会弹出用户名的输入提示。它会根据该 用户的 shell 环境 或者会依据 本地系统的密码库 (支持 pwd 模块的平台)来使用 当前用户的登录名
在bash中编写pytohn脚本接收外部数据的方式,一般情况下,对于一般变量,我们用命令行变量的方式比较多(手动的处理 sys.argv ),对于 文件内容或者bash命令输出 直接通过脚本内部获取需要的数据。
其实python 脚本也可以用其他方式来接收 传递给他的 文件数据或者bash命令输出 ,包括将 命令行的输出 通过 管道传递 给该脚本、 重定向文件到该脚本 ,或在 命令行中传递一个文件名 或 文件名列表 给该脚本。
这里通过 Python 内置的 fileinput 模块 ,可以实现重 定向,管道,以文佳输出 的方式传递数据到脚本内部
使用 fileinput.input() 方法可以获取当前输入脚本的数据,脚本里面用一个 FileInput 迭代器接收
文件直接接收
重定向接收
管道方式接收
fileinput.input() 创建并返回一个 FileInput 类的实例,该实例可以被当做一个 上下文管理器 使用。因此,整合起来,如果我们要写一个打印多个文件输出的脚本,那么我们需要在输出中包含文件名和行号
“你想执行一个外部命令并以 Python 字符串的形式获取执行结果。”
使用 subprocess.check_output() 函数。
执行下试试
如果被执行的命令以非零码返回,就会抛出异常。下面的例子捕获到错误并获取返回码:
默认情况下, check_output() 仅仅返回输入到标准输出的值。如果你需要 同时收集标准输出和错误输出 ,使用 stderr 参数:
如果你需要用一个超时机制来执行命令,使用 timeout 参数:
通常来讲,命令的执行 不需要 使用到 底层 shell 环境(比如 sh、bash) 。一个字符串行表会被传递给一个 低级系统命令 ,比如 os.execve() 。
如果你想让 命令被一个shell 执行 ,传递一个字符串参数,并设置参数 shell=True . 有时候你想要 Python 去执行一个复杂的 shell 命令 的时候这个就很有用了,比如管道流、I/O 重定向和其他特性。例如:
是在 shell 中执行命令会存在一定的安全风险,特别是当参数来自于用户输入时。这时候可以使用 shlex.quote() 函数 来将参数正确的用双引用引起来。
使用 check_output() 函数 是执行 外部命令 并获取其 返回值 的最简单方式。但是,如果你需要对 子进程做更复杂的交互 ,比如给它发送输入,你得采用另外一种方法。这时候可直接使用 subprocess.Popen 类。
关于子进程,简单来看下
也可以进程列表同协程结合的方式。你既可以在子shell中 进行繁重的处理工作,同时也不会让子shell的I/O受制于终端。
如果直接丢到后台会自动在终端输出IO
subprocess 模块对于依赖 TTY 的外部命令不合适用 。例如,你不能使用它来自动化一个用户输入密码的任务(比如一个 ssh 会话)。这时候,你需要使用到第三方模块了,比如基于着名的 expect 家族的工具(pexpect 或类似的)(pexpect可以理解为Linux下的expect的Python封装、通过pexpect可以实现对ssh、ftp、passwd、telnet等命令行进行自动交互,而无需人工干涉来达到自动化的目的。比如我们可以模拟一个FTP登录时所有交互,包括输入主机地址、用户名、密码、上传文件等,待出现异常还可以进行尝试自动处理。)
“你想向标准错误打印一条消息并返回某个非零状态码来终止程序运行”
通过 python 的 raise SystemExit(3) 命令可以主动抛出一个错误,通过 sys.stderr.write 将命令写到标准的输出端
直接将消息作为参数传给 SystemExit() ,那么你可以省略其他步骤
抛出一个 SystemExit 异常,使用错误消息作为参数,它会将消息在 sys.stderr 中打印,然后程序以状态码 1 退出
“你需要知道当前终端的大小以便正确的格式化输出。”
使用 os.get terminal size() 函数 来做到这一点。
“复制或移动文件和目录,但是又不想调用 shell 命令。”
shutil 模块 有很多便捷的函数可以复制文件和目录。使用起来非常简单
这里不多讲,熟悉Linux的小伙伴应该不陌生。
默认情况下,对于 符号链接 这些命令处理的是它指向的东西文件。例如,如果 源文件 是一个 符号链接 ,那么目标文件将会是 符号链接 指向的文件。如果你只想 复制符号链接本身 ,那么需要指定 关键字 参数 follow_symlinks
tree() 可以让你在复制过程中选择性的忽略某些文件或目录。你可以提供一个忽略函数,接受一个目录名和文件名列表作为输入,返回一个忽略的名称列表。例如:
对于文件元数据信息, 2() 这样的函数只能尽自己最大能力来保留它。 访问时间、创建时间和权限 这些基本信息会被保留,但是 对于所有者、ACLs、资源 fork 和其他更深层次的文件元信息就说不准了
通常不会去使用 shutil.tree() 函数 来执行 系统备份 。当处理文件名的时候,最好使用 os.path 中的函数来确保最大的可移植性
使用 tree() 复制文件夹的一个棘手的问题是对于错误的处理,可以使用异常块处理,或者通过 参数 ignore dangling symlinks=True 忽略掉无效符号链接。
“创建或解压常见格式的归档文件(比如.tar, .tgz 或.zip)”
shutil 模块拥有两个函数—— make archive() 和 unpack archive() 可派上用场,
make archive() 的第二个参数是期望的输出格式。可以使用 get archive formats() 获取所有支持的归档格式列表。
“你需要写一个涉及到文件查找操作的脚本,比如对日志归档文件的重命名工具,你不想在 Python 脚本中调用 shell,或者你要实现一些 shell 不能做的功能。”
查找文件,可使用 os.walk() 函数 ,传一个顶级目录名给它
os.walk() 方法 为我们 遍历目录树 ,每次进入一个目录,它会返回一个 三元组 ,包含 相对于查找目录的相对路径,一个该目录下的目录名列表,以及那个目录下面的文件名列表。
对于每个元组,只需检测一下目标文件名是否在文件列表中。如果是就使用 os.path.join() 合并路径。为了避免奇怪的路径名比如 ././foo//bar ,使用了另外两个函数来修正结果
os.walk(start) 还有跨平台的优势。并且,还能很轻松的加入其他的功能。我们再演示一个例子,下面的函数打印所有最近被修改过的文件:
打印10分钟之前被修改的数据
“怎样读取普通.ini 格式的配置文件?”
configparser 模块 能被用来读取配置文件
编写配置文件
如果有需要,你还能修改配置并使用 cfg.write() 方法将其写回到文件中
“你希望在脚本和程序中将诊断信息写入日志文件。”
python 脚本打印日志最简单方式是使用 logging 模块
五个日志调用( critical(), error(), warning(), info(), debug() )以降序方式表示不同的严重级别。 basicConfig() 的 level 参数是一个 过滤器 。所有级别低于此级别的日志消息都会被忽略掉。每个 logging 操作的参数是一个消息字符串,后面再跟一个或多个参数。构造最终的日志消息的时候我们使用了 % 操作符来格式化消息字符串。
如果你想使用配置文件,可以像下面这样修改 basicConfig() 调用:
logconfig.ini
在调用日志操作前先执行下 basicConfig() 函数方法 ,可以找标准输出或者文件中输出
basicConfig() 在程序中只能被执行一次。如果你稍后想改变日志配置,就需要先获取 root logger ,然后直接修改它。
更多见日志模块文档https://docs.python.org/3/howto/logging-cookbook.html
“你想给某个函数库增加日志功能,但是又不能影响到那些不使用日志功能的程序。”
对于想要执行日志操作的函数库,你应该创建一个专属的 logger 对象,并且像下面这样初始化配置:
使用这个配置,默认情况下不会打印日志,只有配置过日志系统,那么日志消息打印就开始生效
通常来讲,不应该在函数库代码中 自己配置日志系统 ,或者是已经有个已经存在的日志配置了。调用 getLogger( name ) 创建一个和调用模块同名的 logger 模块 。由于 模块 都是唯一的,因此创建的 logger 也将是唯一 的。所以当前进程中只有一个logging会生效。
log.addHandler(logging.NullHandler()) 操作将一个 空处理器 绑定到刚刚已经创建好的 logger 对象 上。一个空处理器默认会忽略调用所有的日志消息。因此,如果使用该函数库的时候还没有配置日志,那么将不会有消息或警告出现。
在这里,根日志被配置成仅仅 输出 ERROR 或更高级别的消息 。不过, somelib 的日志级别被单独配置成可以输出 debug 级别的消息, 它的优先级比全局配置高。像这样更改单独模块的日志配置对于调试来讲是很方便的,因为你无需去更改任何的全局日志配置——只需要修改你想要更多输出的模块的日志等级。(这个还有待研究)
“你想记录程序执行多个任务所花费的时间”
time 模块 包含很多函数来执行跟时间有关的函数。尽管如此,通常我们会在此基础之上构造一个更高级的接口来模拟一个计时器。
这个类定义了一个可以被用户根据需要启动、停止和重置的计时器。它会在elapsed 属性中记录整个消耗时间。下面是一个例子来演示怎样使用它:
这里通过 __enter__,__exit__ ,使用 with 语句 以及上下文管理器协议可以省略计时器打开和关闭操作。(关于上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明 __enter__和__exit__方法, , __enter__ 在出现with语句被调用, __exit__ 在代码执行完毕被调用,可以参考open()方法)
在计时中要考虑一个 底层的时间函数问题 。 一般来说, 使用 time.time() 或 time.clock() 计算的时间精度因操作系统的不同会有所不同。而使用 time.perf_counter() 函数可以确保使用系统上面 最精确的计时器 。
“你想对在 Unix 系统上面运行的程序设置内存或 CPU 的使用限制。”
resource 模块 能同时执行这两个任务。例如,要限制 CPU 时间,下面的代码在windows平台执行不了,但是Linux是可以的。
程序运行时, SIGXCPU 信号 在时间过期时被生成,然后执行清理并退出。
这暂时没有好的Demo...
程序运行到没有多余内存时会抛出 MemoryError 异常。
setrlimit() 函数 被用来设置特定资源上面的 软限制和硬限制 。
setrlimit() 函数 还能被用来设置 子进程数量、打开文件数以及类似系统资源的限制(cgroup) 。
“通过脚本启动浏览器并打开指定的 URL 网页”
webbrowser 模块 能被用来启动一个浏览器,并且与平台无关
新窗口打卡网站
当前窗口打开一个tab页
指定浏览器类型,可以使用 webbrowser.get() 函数
⑹ 如何使用批处理执行python脚本,并把python脚本的控制台日志输出到一个log文件中
1, 用绝对路径试试:D:\logs\log.txt;
2, 最后的exit去掉试试,反正最后一行执行完也会自然退出。
3, 另写一个简单的python测试脚本,里面只有一行 print 'Hello World', 然后用上述批处理执行一下看看log对不对。
⑺ 怎样把空间日志中的文章打印下来(注:无法复制)
我们在上网的时候看到喜欢的文字和图片就想复制下来保存到本地硬盘中慢慢欣赏,可是有些网站为了保护自己的内容就运用了一些技术手段让我们无法镇旦复制。在有些网页中,使用鼠标拖动的方法,不能选中文字,当然也就不能复制网页中的文字。其实这种难题也是右办法解决的,你可以进行这样的操作:在IE浏览器中,选择“工具”菜单中的“Internet选项”,在打开的“Internet选项”对话搜旅帆框中,选择“安全”选项卡,单击“自定义级别”按钮,打开(如图1)所示的“安全设置”对话框,将所有脚本全部禁用,然后按F5键刷新网页世雹,这时网页中那些无法选取的文字就可以选区了。
⑻ 执行一sql脚本如,怎么样才能输出执行日志到文本文件中
执行一SQL脚本如,怎么样才能输出执行日志到文本文件中
这个方法可以,要在sqlplus的环境里执行,
也可以直接在cmd里执行
sqlplus "username/password@tnaname"@abc.sql > result.log
比如
sqlplus "test1/test@orcl"@test.sql > result.log
⑼ 求助:如何在shell脚本中添加写日志的功能
如何编写一个shell脚本本文结合大量实例阐述如何编写一个shell脚本。为什么要进行shell编程在Linux系统中,虽然有各种各样的图形化接口工具,但是sell仍然是一个非常灵活的工具。Shell不仅仅是命令的收集,而且是一门非常棒的编程语言。您可以通过使用shell使大量的任务自动化,shell特别擅长系统管理任务,尤其适合那些易用性、可维护性和便携性比效率更重要的任务。下面,让我们一起来看看shell是如何工作的:建立一个脚本Linux中有好多中不同的shell,但是通常我们使用bash(bourneagainshell)进行shell编程,因为bash是免费的并且很容易使用。所以在本文中笔者所提供的脚本都是使用bash(但是在大多数情况下,这些脚本同样可以在bash的大姐,bourneshell中运行)。如同其他语言一样,通过我们使用任意一种文字编辑器,比如nedit、kedit、emacs、vi等来编写我们的shell程序。程序必须以下面的行开始(必须方在文件的第一行):#!/bin/sh符号#!用来告诉系统它后面的参数是用来执行该文件的程序。在这个例子中我们使用/bin/sh来执行程序。当编辑好脚本时,如果要执行该脚本,还必须使其可执行。要使脚本可执行:chmod+xfilename然后,您可以通过输入:./filename来执行您的脚本。注释在进行shell编程时,以#开头的句子表示注释,直到这一行的结束。我们真诚地建议您在程序中使用注释。如果您使用了注释,那么即使相当长的时间内没有使用该脚本,您也能在很短的时间内明白该脚本的作用及工作原理。变量在其他编程语言中您必须使用变量。在shell编程中,所有的变量都由字符串组成,并且您不需要对变量进行声明。要赋值给一个变量,您可以这样写:变量名=值取出变量值可以加一个美元符号($)在变量前面:#!/bin/sh#对变量赋值:a="helloworld"#现在打印变量a的内容:echo"Ais:"echo$a在您的编辑器中输入以上内容,然后将其保存为一个文件first。之后执行chmod+xfirst使其可执行,最后输入./first执行该脚本。这个脚本将会输出:Ais:helloworld有时候变量名很容易与其他文字混淆,比如:num=2echo"thisisthe$numnd"这并不会打印出"thisisthe2nd",而仅仅打印"thisisthe",因为shell会去搜索变量numnd的值,但是这个变量时没有值的。可以使用花括号来告诉shell我们要打印的是num变量:num=2echo"thisisthe${num}nd"这将打印:thisisthe2nd有许多变量是系统自动设定的,这将在后面使用这些变量时进行讨论。如果您需要处理数学表达式,那么您需要使用诸如expr等程序(见下面)。除了一般的仅在程序内有效的shell变量以外,还有环境变量。由export关键字处理过的变量叫做环境变量。我们不对环境变量进行讨论,因为通常情况下仅仅在登录脚本中使用环境变量。Shell命令和流程控制在shell脚本中可以使用三类命令:1)Unix命令:虽然在shell脚本中可以使用任意的unix命令,但是还是由一些相对更常用的命令。这些命令通常是用来进行文件和文字操作的。常用命令语法及功能echo"sometext":将文字内容打印在屏幕上ls:文件列表wc–lfilewc-wfilewc-cfile:计算文件行数计算文件中的单词数计算文件中的字符数cpsourcefiledestfile:文件拷贝mvoldnamenewname:重命名文件或移动文件rmfile:删除文件grep'pattern'file:在文件内搜索字符串比如:grep'searchstring'file.txtcut-bcolnumfile:指定欲显示的文件内容范围,并将它们输出到标准输出设备比如:输出每行第5个到第9个字符cut-b5-9file.txt千万不要和cat命令混淆,这是两个完全不同的命令catfile.txt:输出文件内容到标准输出设备(屏幕)上filesomefile:得到文件类型readvar:提示用户输入,并将输入赋值给变量sortfile.txt:对file.txt文件中的行进行排序uniq:删除文本文件中出现的行列比如:sortfile.txt|uniqexpr:进行数学运算Example:add2and3expr2"+"3find:搜索文件比如:根据文件名搜索find.-namefilename-printtee:将数据输出到标准输出设备(屏幕)和文件比如:somecommand|teeoutfilebasenamefile:返回不包含路径的文件名比如:basename/bin/tux将返回tuxdirnamefile:返回文件所在路径比如:dirname/bin/tux将返回/binheadfile:打印文本文件开头几行tailfile:打印文本文件末尾几行sed:Sed是一个基本的查找替换程序。可以从标准输入(比如命令管道)读入文本,并将结果输出到标准输出(屏幕)。该命令采用正则表达式(见参考)进行搜索。不要和shell中的通配符相混淆。比如:将linuxfocus替换为LinuxFocus:cattext.file|sed's/linuxfocus/LinuxFocus/'>newtext.fileawk:awk用来从文本文件中提取字段。缺省地,字段分割符是空格,可以使用-F指定其他分割符。catfile.txt|awk-F,'{print$1","$3}'这里我们使用,作为字段分割符,同时打印第一个和第三个字段。如果该文件内容如下:AdamBor,34,IndiaKerryMiller,22,USA命令输出结果为:AdamBor,IndiaKerryMiller,USA2)概念:管道,重定向和backtick这些不是系统命令,但是他们真的很重要。管道(|)将一个命令的输出作为另外一个命令的输入。grep"hello"file.txt|wc-l在file.txt中搜索包含有”hello”的行并计算其行数。在这里grep命令的输出作为wc命令的输入。当然您可以使用多个命令。重定向:将命令的结果输出到文件,而不是标准输出(屏幕)。>写入文件并覆盖旧文件>>加到文件的尾部,保留旧文件内容。反短斜线使用反短斜线可以将一个命令的输出作为另外一个命令的一个命令行参数。命令:find.-mtime-1-typef-print用来查找过去24小时(-mtime–2则表示过去48小时)内修改过的文件。如果您想将所有查找到的文件打一个包,则可以使用以下脚本:#!/bin/sh#Theticksarebackticks(`)notnormalquotes('):tar-zcvflastmod.tar.gz`find.-mtime-1-typef-print`3)流程控制"if"表达式如果条件为真则执行then后面的部分:if.;then.elif.;then.else.fi大多数情况下,可以使用测试命令来对条件进行测试。比如可以比较字符串、判断文件是否存在及是否可读等等…通常用"[]"来表示条件测试。注意这里的空格很重要。要确保方括号的空格。[-f"somefile"]:判断是否是一个文件[-x"/bin/ls"]:判断/bin/ls是否存在并有可执行权限[-n"$var"]:判断$var变量是否有值["$a"="$b"]:判断$a和$b是否相等执行mantest可以查看所有测试表达式可以比较和判断的类型。直接执行以下脚本:#!/bin/shif["$SHELL"="/bin/bash"];thenecho"yourloginshellisthebash(bourneagainshell)"elseecho"yourloginshellisnotbashbut$SHELL"fi变量$SHELL包含了登录shell的名称,我们和/bin/bash进行了比较。快捷操作符熟悉C语言的朋友可能会很喜欢下面的表达式:[-f"/etc/shadow"]&&echo""这里&&就是一个快捷操作符,如果左边的表达式为真则执行右边的语句。您也可以认为是逻辑运算中的与操作。上例中表示如果/etc/shadow文件存在则打印””。同样或操作(||)在shell编程中也是可用的。这里有个例子:#!/bin/shmailfolder=/var/spool/mail/james[-r"$mailfolder"]''{echo"Cannotread$mailfolder";exit1;}echo"$mailfolderhasmailfrom:"grep"^From"$mailfolder该脚本首先判断mailfolder是否可读。如果可读则打印该文件中的"From"一行。如果不可读则或操作生效,打印错误信息后脚本退出。这里有个问题,那就是我们必须有两个命令:-打印错误信息-退出程序我们使用花括号以匿名函数的形式将两个命令放到一起作为一个命令使用。一般函数将在下文提及。不用与和或操作符,我们也可以用if表达式作任何事情,但是使用与或操作符会更便利很多。case表达式可以用来匹配一个给定的字符串,而不是数字。casein)dosomethinghere;;esac让我们看一个例子。file命令可以辨别出一个给定文件的文件类型,比如:filelf.gz这将返回:lf.gz:gzipcompresseddata,deflated,originalfilename,lastmodified:MonAug2723:09:182001,os:Unix我们利用这一点写了一个叫做smartzip的脚本,该脚本可以自动解压bzip2,gzip和zip类型的压缩文件:#!/bin/shftype=`file"$1"`case"$ftype"in"$1:Ziparchive"*)unzip"$1";;"$1:gzipcompressed"*)gunzip"$1";;"$1:bzip2compressed"*)bunzip2"$1";;*)error"File$";;esac您可能注意到我们在这里使用了一个特殊的变量$1。该变量包含了传递给该程序的第一个参数值。也就是说,当我们运行:smartziparticles.zip$1就是字符串articles.zipselect表达式是一种bash的扩展应用,尤其擅长于交互式使用。用户可以从一组不同的值中进行选择。selectvarin;dobreakdone.now$varcanbeused.下面是一个例子:#!/bin/shecho"WhatisyourfavouriteOS?"selectvarin"Linux""GnuHurd""FreeBSD""Other";dobreakdoneecho"Youhaveselected$var"下面是该脚本运行的结果:WhatisyourfavouriteOS?1)Linux2)GnuHurd3)FreeBSD4)Other#?1YouhaveselectedLinux您也可以在shell中使用如下的loop表达式:while;do.donewhile-loop将运行直到表达式测试为真。.关键字"break"用来跳出循环。而关键字”continue”用来不执行余下的部分而直接跳到下一个循环。for-loop表达式查看一个字符串行表(字符串用空格分隔)然后将其赋给一个变量:forvarin.;do.done在下面的例子中,将分别打印ABC到屏幕上:#!/bin/shforvarinABC;doecho"varis$var"done下面是一个更为有用的脚本showrpm,其功能是打印一些RPM包的统计信息:#!/bin/sh##USAGE:showrpmrpmfile1rpmfile2#EXAMPLE:showrpm/cdrom/RedHat/RPMS/*.rpmforrpmpackagein$*;doif[-r"$rpmpackage"];thenecho"===============$rpmpackage=============="rpm-qi-p$rpmpackageelseecho"ERROR:cannotreadfile$rpmpackage"fidone这里出现了第二个特殊的变量$*,该变量包含了所有输入的命令行参数值。如果您运行showrpmopenssh.rpmw3m.rpmwebgrep.rpm此时$*包含了3个字符串,即openssh.rpm,w3m.rpmandwebgrep.rpm.引号在向程序传递任何参数之前,程序会扩展通配符和变量。这里所谓扩展的意思是程序会把通配符(比如*)替换成合适的文件名,它变量替换成变量值。为了防止程序作这种替换,您可以使用引号:让我们来看一个例子,假设在当前目录下有一些文件,两个jpg文件,mail.jpg和tux.jpg。#!/bin/shecho*.jpg这将打印出"mail.jpgtux.jpg"的结果。引号(单引号和双引号)将防止这种通配符扩展:#!/bin/shecho"*.jpg"echo'*.jpg'这将打印"*.jpg"两次。单引号更严格一些。它可以防止任何变量扩展。双引号可以防止通配符扩展但允许变量扩展。#!/bin/shecho$SHELLecho"$SHELL"echo'$SHELL'运行结果为:/bin/bash/bin/bash$SHELL最后,还有一种防止这种扩展的方法,那就是使用转义字符——反斜杆:echo*.jpgecho$SHELL这将输出:*.jpg$SHELLHeredocuments当要将几行文字传递给一个命令时,heredocuments(译者注:目前还没有见到过对该词适合的翻译)一种不错的方法。对每个脚本写一段帮助性的文字是很有用的,此时如果我们四有那个heredocuments就不必用echo函数一行行输出。一个"Heredocument"以shiftby2--)shift;break;;#endofoptions-*)echo"error:nosuchoption$1.-hforhelp";exit1;;*)break;;esacdoneecho"opt_fis$opt_f"echo"opt_lis$opt_l"echo"firstargis$1"echo"2ndargis$2"您可以这样运行该脚本:cmdparser-lhello-f---somefile1somefile2返回的结果是:opt_fis1opt_lishellofirstargis-somefile12ndargissomefile2这个脚本是如何工作的呢?脚本首先在所有输入命令行参数中进行循环,将输入参数与case表达式进行比较,如果匹配则设置一个变量并且移除该参数。根据unix系统的惯例,首先输入的应该是包含减号的参数。实例一般编程步骤现在我们来讨论编写一个脚本的一般步骤。任何优秀的脚本都应该具有帮助和输入参数。并且写一个伪脚本(framework.sh),该脚本包含了大多数脚本都需要的框架结构,是一个非常不错的主意。这时候,在写一个新的脚本时我们只需要执行一下命令:cpframework.shmyscript然后再插入自己的函数。让我们再看两个例子:二进制到十进制的转换脚本b2d将二进制数(比如1101)转换为相应的十进制数。这也是一个用expr命令进行数学运算的例子:#!/bin/sh#vim:setsw=4ts=4et:help(){cat<
⑽ 如何打印一个脚本执行时的日志
把脚本输出重定向到日志文件
scripts.sh > file.log 2>&1