在Unix操作系统中可以利用echo与printf两个回显命令来实现。但是到底用哪个命令好呢?笔者先给出一个答案,然后再进行说明。通常情况下,笔者建议操作系统工程师最好使用printf命令,而不是采用echo命令。除非在你原来的程序中就带有很多的echo命令,为了统一性的考虑继续沿用echo命令。一般来说只要是新编写的脚本程序,最好都能够利用printf命令来替代echo命令。
** 一、echo命令的缺陷分析。**
Echo命令可以说是Unix操作系统命令中的老祖宗了。这个命令主要用来在终端显示相关的信息,如当前的环境变量、显示提示信息等等。在刚开始的时候,echo是一个外部命令,而现在基本上所有的外壳程序中都内置了这个echo命令。而根据内部命令优先的原则,那个外部命令文件就变成了摆设,基本没用。虽然说echo命令比较老,其出现在Unix系统统一规范之前,故其有比较大的缺陷。如果利用echo命令作为Unix操作系统中的回显命令,就觉得不怎么合适。
1、echo在不同的外壳程序中用法不统一,导致脚本程序兼容性差。如在实际脚本程序开发过程中,往往需要通过一些转义字符来控制提示信息的显示位置。如echo “\n Please input your Student Num:”表示换一行显示提示信息。但是这些转义字符可能在不同的外壳程序中代表不同的含义;又或者说有的外壳程序支持某个转义字符,而有的外壳程序不支持。所以说,如果在脚本程序中采用echo作为回显命令的话,则很可能在不同的外壳环境中,其最终显示的结果会有很大的差异,其兼容性不好。通常这种情况下,系统工程师需要预先利用IF语句来判断当前所采用的外壳程序,然后再根据外壳程序的种类选择执行合适的echo语句(各个echo语句根据外壳程序支持的转义字符不同而采用不同的转义字符或者相应的语法)。这么处理的话虽然可行,但是无疑增加了脚本的代码量。而且当脚本程序比较复杂时,也会影响其执行的性能。
2、其功能不够强大。虽然echo命令出现的比较早,但是这个命令的功能这么多年来没有多大的扩展。如上例所示,学生的编号可能为8个整数型的数字。而利用echo命令就无法控制内容输出的格式,而且也无法控制输出字符串的宽度等等。所以说echo命令的功能比较有限。如果要利用echo命令开显示一些复杂的信息时,往往还需要通过其他的一些语句来帮助。所以说,现在echo命令往往只是在shell中简单的回显一些信息,如当前的环境变量等等。而越来越少的系统工程师会在编写脚本程序的过程中用到这个命令。
综上所述,在编写脚本程序的过程中,echo命令正在逐渐退出舞台。虽然其具有比较久远的历史,但是由于其功能上、兼容性上的一些缺陷,系统工程师现在很少会采用echo命令来编写脚本程序。但是在脚本程序的运行中,终端中仍然需要输出一些有用的信息。既然系统工程师有这方面的需要,而echo命令又无法真正的满足这个需要。在市场有需求的情况下,就必定会出来一个合用的替代品。Printf命令就在这种背景下应用而生了。
** 二、Printf命令优势分析。**
printf命令也是一个回显命令,使Unix操作系统的外部命令。到目前为止,只有bash shell外壳程序中把这个命令当作内部命令。虽然这有点细小的差异,但是这并不会影响这个命令的兼容性问题。那么这个命令与echo命令相比,具有什么优势呢?为什么这个命令为成为echo命令的最合适的替代品呢?
1、这个命令的兼容性比较高。这个printf命令所采用的字符串格式与c语言程序中的一个同名函数使用的字符串格式一模一样。也就是说,在C语言中也有这么一个printf函数,其所采用的字符串格式是相同的。而众所周知,虽然现在Unix操作系统有不同的版本,其外壳程序也多达四种。但是他们都是通过C语言来开发完成的。所以说,这个Printf命令就可以在当前的Unix操作系统中使用,其可以兼容所有的外壳程序。这是echo命令所无法替代的。由于兼容性比较高,那么在编写脚本程序的时候就不用去判断当前使用的shell到底是哪一种了。这可以节省不少的代码编写,提高脚本程序的开发效率。同时,同一个脚本程序在不同的shell中运行,其最终显示的结果都是一样的。这种兼容性正式系统工程师在编写脚本程序时所追求的。
2、在printf命令中,还可以对输入字符串的内容进行格式化与显示宽度的控制。如%30s,就表示一个字符串格式,并且输出的宽度为30个字符。如果实际的字符超过这个最大宽度的话,超过部分的内容就不会被显示,或者进行分行等等。这个格式化与宽度的控制,在实际工作中非常有用。如可以通过这个功能,格式化显示结果。当显示的结果有多条记录时,还可以让其看起来列与列之间更加的整齐,从而提高显示结果的可读性。另外由于不同的数据类型其显示的格式是不同的。Printf命令还可以根据显示结果的内容不同而采用不同的输出格式。如%f表示输出的格式是浮点数格式,就会以预定义的浮点数格式来显示结果;如%d则表示十进制的整数,就会以十进制的整数来显示结果 。
3、一般来说,printf命令具有echo命令的全部功能。但是有些echo命令无法实现的功能则在echo命令中就有。如在开发一些网络管理工具的时候,需要把十进制的IP地址转换为二进制的数字,以方便进行子网的设计。也就是说,用户输入一个十进制的IP地址,然后再终端输出这个十进制的IP地址所对应的二进制数据。要实现这个功能的话,通过printf命令就可以轻松实现。但是如果采用echo命令的话,则还需要通过其他的命令来完成。这也是为什么许多系统工程师放弃echo命令而采用printf命令的一个重要原因。
另外在使用这个printf命令的时候,需要注意两个问题。
首先,printf命令虽然可是实现大部分的功能,其字符串格式跟C语言中的Printf函数相同。但是其毕竟是Unix操作系统中的一个外部命令,为此其与C语言中的函数使用方法还有很大的不同。笔者以前学过C语言,后来学Unix系统开发的时候,就不怎么适应,老是出错。所以系统工程师在这方面需要注意。根据笔者的了解,与C语言中的Printf函数主要有两个方面的不同。一是其功能没有C语言中的Printf函数那么强。有些在C语言中可以实现的功能,但是在Unix操作系统中的Printf命令却无法实现。故如果系统工程师比较熟悉C语言,而对于Unix操作系统中的Printf命令不怎么熟悉的话,则在使用的过程中需要确认一下这个功能是否在Unix操作系统中也支持。二是在用法上也会有细微的差异。在C语言中,Printf是一个函数。而在给函数传递传输的时候,必须要使用括号;另外各个参数以及各个格式之间必须要利用逗号分割。但是在Unix操作系统中,Printf只是一个命令,不需要使用括号。
其次在使用Printf命令的时候,双引号是可选的。也就是说,Printf “abcd” 与 Printf abcd 是等价的。但是笔者建议还是需要加上这个双引号,虽然输入的过程可能麻烦一点。如需要显示的内容是中文的,但是这个双引号则是英文状态下的双引号,需要进行切换。这主要是出于程序的可读性考虑。如果不加双引号的话,则很可能跟其他的参数混合。另外,也有利于系统命令解释器的处理。
具体用法如下:
echo是非常常用的shell命令。参数如下:
\a : 发出警告铃音(ALERT or CTRL-G (bell))
\b : 退格(BACKSPACE or CTRL-H )
\c : 删除最后的字符及最后的换行(Omit final NEWLINE )
\e : 删除后面的一个字符(Escape character (same as \E) )
\E : 同上(Escape character)
\f : 换页符,在某些现实中会清屏,有些会换行(FORMFEED or CTRL-L )
\n : 换行(NEWLINE (not at end of command) or CTRL-J )
\r : 从行头开始,和换行不一样,仍在本行(RETURN (ENTER) or CTRL-M )
\t : tab键(TAB or CTRL-I )
\v : 竖直tab,和\f一样,显示不同机器有所不一样,通常会引起换行VERTICAL TAB or CTRL-K
**_n_ **: 在cygwin中使用\65,无法正确显示’A’但是下面两种方法否可以显示。ASCII character with octal (base-8) value n, where n is 1 to 3 digits
**\0nnn **: 用8进制的值表示一个字符,例如\0101,即65,表示字符’A’(The eight-bit character whose value is the octal (base-8) value nnn where nnn is 1 to 3 digits )
**\x_HH_ **: 用16进制的值表示一个字符,例如\x41,即65,表示字符’A’The eight-bit character whose value is the hexadecimal (base-16) value HH (one or two digits)
\ : 表示’'Single backslash 倒数第2-4,用数值来表示字符和设备相关,通常用于复杂的IO操作,例如光标控制和特殊的图形符号。
printf
Linux提供一个功能更强大,更灵活的打印命令printf。printf和C语言的使用方式类似。和echo不一样,它不会在最后自动加上换行,需要写入命令中。例如printf “Hello, world\n”。printf的命令格式如下:
printf format-string [arguments] 例子为:printf “%s, %s\n” hello world。如果格式需要的参数比后面给出的多,超出的部分为0或者null。格式如下。 %c:ASCII字符,如果参数给出字符串,则打印第一个字符
%d:10进制整数
%i:同%d
%e:浮点格式([-]d.精度[+-]dd)
%E:浮点格式([-]d.精度E[+-]dd)
%f:浮点格式([-]ddd.precision)
%g:%e或者%f的转换,如果后尾为0,则删除它们
%G:%E或者%f的转换,如果后尾为0,则删除它们
%o:8进制
%s:字符串
%u:非零正整数
%x:十六进制
%X:非零正数,16进制,使用A-F表示10-15
%%:表示字符”%” 如果需要限定输出的宽度,格式为%flags width.precision format-specifier,width是整数,右边对齐,如果需要左边对齐,在前面加”-“,例如”%-20s”表示从左边开始对齐,宽度为20,如果字符串长度少于20,通过空格补齐。precision在浮点值中提供四舍五入。例如%5.6G,长度为5,精度为6。精度是可选的。长度和精度的值可以参数中指定,例如printf “%.G\n” 5 6 $myvalue。长度指显示中占的字符长度,与字符长度的同义。如果长度比实际的少,例如实际字符长度更大或者所要求的精度更大,则显示按实际长度。 %d, %I, %o, %u, %x, %X:在里面使用精度,表示最小显示的数字。如果显示的数字比需求少,则补充0。缺省值为1.
%e, %E:在里面使用精度,表示最小显示的数字。如果显示的数字比需求少,在小数点后面补充0。缺省值为10.精度度为0经隐藏小数点。
%f:在这里的精度,表示小数点后面的数字的数目。
%g, %G:这里的精度,表示最大的有效数字的数目。
%s:这里的精度,表示最大的字符数目。 在前面,介绍了”-“作为左对齐,下面介绍这些特殊符号 -:左对齐
space:正数前面加空格,负数前面加符号,例如12.12,’% f’,显示’ 12.120000’,注意前面留了一个空格。例如-12.12,’% f’,显示’-12.120000’
+:对于数码给予正负号。
#:给出另一种格式:
- %o以8进制显示整数,而%#o则在前面加上零,表明是八进制,例如12,显示014
- %x或者%X以16进制的方式显示整数,而%#x或者%#X,在16进制的整数前面加上0x或者0X来表示,例如12,显示0XC
- %#e,%#E, %#f,将只以十进制显示
- %#g,%#G,将不删除最后无关的补齐0,例如12.1200,将全部显示,而不是12.12。
0:对于数目,不使用空格,而使用0来作为补齐。 介绍两个特别的字符显示格式%b和%q。 %b:表示解析字符串的特殊的字符,包括\n等等。例如printf “%s\n” ‘hello\nworld’,显示hello\nworld,要将\n作为换行符,则需要用printf “%b\n” ‘hello\nworld’ 。
%q:printf “%q\n” “greetings to the world”显示为greetings\ to\ the\ world,可以作为shell的输入。