Unix/Linux 系统管理与操作效率提升技巧
在 Unix/Linux 系统的使用过程中,我们常常会面临各种管理和操作上的问题。下面将为大家详细介绍一些实用的技巧和方法,帮助大家更高效地完成系统管理任务。
1. 进程搜索与正则表达式匹配
在使用ps和grep进行进程搜索时,有一些要点需要注意。在$( )周围加上双引号" ",这样当grep有输出时,测试结果为真;若grep因无匹配项而无输出,则测试结果为假。同时,要确保ps和grep命令能准确实现预期功能。
需要注意的是,ps命令在不同的 Unix 和 Linux 系统中差异较大,每个系统可能有不同的参数和处理方式。因此,必须在脚本运行的所有系统上进行全面测试。
使用正则表达式搜索时,要保证表达式足够具体,避免匹配到无关内容。例如,使用bin/[s]shd而非[s]shd,因为后者可能会匹配到用户连接。不过,/usr/sbin/[s]shd也可能存在问题,因为有些系统可能不使用该路径。在特异性方面,需要把握好度,避免过度或不足。比如,对于可使用不同配置文件运行多个实例的程序,若要隔离正确的实例,需同时搜索配置文件;若有足够权限查看其他用户的进程,对用户的搜索也需注意。
另外,在 Solaris 系统中,ps命令的参数长度被硬编码限制为 80 个字符。如果路径或命令较长且需要检查配置文件名,可能会达到这个限制。
2. 为输出添加前缀或后缀
有时候,我们希望为某个命令的输出每行添加前缀或后缀。例如,在从多台机器收集last统计信息时,如果每行都包含主机名,那么后续的grep或数据解析会更方便。
以下是几种实现方法:
-使用while read循环和printf:
$ last | while read i; do [[ -n "$i" ]] && printf "%b" "$HOSTNAME\t$i\n"; done # 写入新的日志文件 $ last | while read i; do [[ -n "$i" ]] && printf "%b" "$HOSTNAME\t$i\n"; done > last_$HOSTNAME.log- 使用
awk:
$ last | awk "BEGIN { OFS=\"\t\" } ! /^\$/ { print \"$HOSTNAME\", \$0}" $ last | awk "BEGIN { OFS=\"\t\" } ! /^\$/ { print \"$HOSTNAME\", \$0}" > last_$HOSTNAME.log使用[[ -n "$i" ]]可去除last输出中的空行,然后用printf显示数据。这种方法的引号使用更简单,但步骤较多(涉及last、while和read,而awk方法只涉及last和awk)。可以根据自身需求选择更易记忆、更易读或更快的方法。
awk命令有个小技巧,通常awk命令用单引号包围,以防止 shell 把awk变量解释为 shell 变量。但这里需要 shell 插值$HOSTNAME,所以用双引号包围命令,同时对不想让 shell 处理的元素(如内部双引号和包含当前行的$0变量)使用反斜杠转义。
若要添加后缀,只需移动$0变量的位置:
$ last | while read i; do [[ -n "$i" ]] && printf "%b" "$i\t$HOSTNAME\n"; done $ last | awk "BEGIN { OFS=\"\t\" } ! /^\$/ { print \$0, \"$HOSTNAME\"}"还可以使用Perl或sed:
$ last | perl -ne "print qq($HOSTNAME\t\$_) if ! /^\s*$/;" $ last | sed "s/./$HOSTNAME ➝ &/; /^$/d"在Perl命令中,使用qq( )代替双引号以避免转义。最后部分是一个正则表达式,用于匹配空行或仅包含空白字符的行,$_是Perl中表示当前行的习惯用法。在sed命令中,将包含至少一个字符的行替换为前缀和匹配到的字符(&),然后删除空行。
3. 为文本文件的行编号
当需要为文本文件的行编号以便参考或作为示例时,可以使用以下方法:
-使用while循环:
$ i=0; while IFS= read -r line; do (( i++ )); echo "$i $line"; done < lines示例输出:
1 Line 1 2 Line 2 3 4 Line 4 5 Line 5 6- 使用
cat命令:
$ cat -n lines输出:
1 Line 1 2 Line 2 3 4 Line 4 5 Line 5 6$ cat -b lines输出:
1 Line 1 2 Line 2 3 Line 4 4 Line 5如果只需要在屏幕上显示行号,可以使用less -N:
$ /usr/bin/less -N filename输出:
1 Line 1 2 Line 2 3 4 Line 4 5 Line 5 6 lines (END)不过,在一些旧版本的 Red Hat 系统上,less的行号功能可能存在问题。可以使用less -V检查版本,已知版本 358+iso254(如 Red Hat 7.3 和 8.0)有问题,版本 378+iso254(如 RHEL3)和版本 382(RHEL4、Debian Sarge)正常,其他版本未测试。问题可能与旧的 iso256 补丁有关,可以通过与vi和Perl示例的最后行号进行比较。
也可以使用vi(或只读的view)结合:set nu!命令:
$ vi filename进入vi后,输入:set nu!,即可显示行号:
1 Line 1 2 Line 2 3 4 Line 4 5 Line 5 6 ~vi有很多选项,例如可以使用vi +3 -c 'set nu!' filename开启行号显示并将光标定位到第 3 行。如果想更灵活地控制行号显示,还可以使用nl、awk或perl:
$ nl lines输出:
1 Line 1 2 Line 2 3 Line 4 4 Line 5$ nl -ba lines输出:
1 Line 1 2 Line 2 3 4 Line 4 5 Line 5 6$ awk '{ print NR, $0 }' filename输出:
1 Line 1 2 Line 2 3 4 Line 4 5 Line 5 6$ perl -ne 'print qq($.\t$_);' filename输出:
1 ➝ Line 1 2 ➝ Line 2 3 ➝ 4 ➝ Line 4 5 ➝ Line 5 6 ➝NR和$.分别是awk和Perl中当前输入文件的行号,使用它们可以轻松打印行号。需要注意的是,Perl输出中用➝表示制表符,而awk默认使用空格。
4. 生成数字序列
为了测试或其他目的,需要生成数字序列,可能还会包含其他文本。可以使用以下方法:
-使用awk:
$ awk 'END { for (i=1; i <= 5; i++) print i, "text"}' /dev/null输出:
1 text 2 text 3 text 4 text 5 text$ awk 'BEGIN { for (i=1; i <= 5; i+=.5) print i}' /dev/null输出:
1 1.5 2 2.5 3 3.5 4 4.5 5在一些系统(如 Solaris)中,awk会等待文件输入,若不指定文件(如/dev/null)会卡住。指定/dev/null对其他系统无影响,可放心使用。注意,print语句中的变量是i,而非$i,若误使用$i,它会被解释为当前处理行的字段,由于这里没有处理行,将得不到任何输出。
BEGIN或END模式可在处理文件时进行启动或清理操作。由于这里不处理文件,需要使用其中一个模式,让awk知道即使没有正常输入也需要执行操作,在这种情况下,使用哪个模式均可。
有一个 GNU 工具seq可以实现相同功能,但在很多系统(如 BSD、Solaris 和 Mac OS X)上默认没有安装。它提供了一些有用的格式化选项,且仅适用于数字。
在 bash 2.04 及更高版本中,可以使用算术整数for循环:
$ for ((i=1; i<=5; i++)); do echo "$i text"; done输出:
1 text 2 text 3 text 4 text 5 text在 bash 3.0 及更高版本中,还支持{x..y}花括号扩展,可用于整数或单个字符:
$ printf "%s text\n" {1..5}输出:
1 text 2 text 3 text 4 text 5 text$ printf "%s text\n" {a..e}输出:
a text b text c text d text e text5. 模拟 DOS Pause 命令
如果你从 DOS/Windows 批处理文件迁移过来,想模拟 DOS 的pause命令,可以使用以下函数:
pause ( ) { read -p 'Press any key when ready...' }-p选项后跟字符串参数,会在读取输入前打印该字符串,这里的字符串与 DOSpause命令的输出相同。
6. 为长数字添加千位分隔符
为长数字添加千位分隔符,可以使用以下方法:
-使用printf:
$ LC_NUMERIC=en_US.UTF-8 printf "%'d\n" 123456789输出:
123,456,789$ LC_NUMERIC=en_US.UTF-8 printf "%'f\n" 123456789.987输出:
123,456,789.987000- 使用 shell 函数:
# cookbook filename: func_commify function commify { typeset text=${1} typeset bdot=${text%%.*} typeset adot=${text#${bdot}} typeset i commified (( i = ${#bdot} - 1 )) while (( i>=3 )) && [[ ${bdot:i-3:1} == [0-9] ]]; do commified=",${bdot:i-2:3}${commified}" (( i -= 3 )) done echo "${bdot:0:i+1}${commified}${adot}" }该 shell 函数的逻辑与人用铅笔和纸处理的过程类似。首先检查字符串,找到小数点(如果有),忽略小数点后的部分,处理小数点前的字符串。函数将小数点前的字符串保存到$bdot中,小数点后的部分(包括小数点)保存到$adot中。如果没有小数点,所有内容都在$bdot中,$adot为空。然后从右向左处理小数点前的部分,当满足以下两个条件时插入逗号:
- 剩余字符数不少于 4 个。
- 逗号前的字符是数字。
这个逻辑在while循环中实现。
- 使用 Perl 函数:
# cookbook filename: perl_sub_commify #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # Add comma thousands separator to numbers # Returns: input string, with any numbers commified # From Perl Cookbook2 2.16, pg 84 sub commify { @_ == 1 or carp ('Sub usage: $withcomma = commify($somenumber);'); my $text = reverse $_[0]; $text =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/g; return scalar reverse $text; }需要注意的是,美国使用逗号作为千位分隔符,而许多其他国家使用句点。
7. 快速在任意目录间切换
在使用系统时,我们经常需要在多个目录之间频繁切换,每次都输入长路径名会很麻烦。可以使用pushd和popd内置命令来管理目录位置栈,实现轻松切换。
以下是一个简单的示例:
$ cd /tmp/tank $ pwd /tmp/tank $ pushd /var/log/cups /var/log/cups /tmp/tank $ pwd /var/log/cups $ ls access_log error_log page_log $ popd /tmp/tank $ ls empty full $ pushd /var/log/cups /var/log/cups /tmp/tank $ pushd /tmp/tank /var/log/cups $ pushd /var/log/cups /tmp/tank $ pushd /tmp/tank /var/log/cups $ dirs /tmp/tank /var/log/cups栈是后进先出的机制,pushd和popd命令的行为符合这一特点。当使用pushd切换到新目录时,会将前一个目录压入栈中;使用popd时,会将当前目录从栈中弹出,回到前一个目录。使用这些命令切换目录时,会按栈的从上到下顺序从左到右打印栈中的值。
如果不带目录参数使用pushd,会交换栈顶的两个元素,这样可以通过重复使用无参数的pushd命令在两个目录之间交替切换,也可以使用cd -命令实现相同效果。
仍然可以使用cd命令切换目录,这会改变当前目录,即目录栈的栈顶。如果忘记了目录栈中的内容,可以使用dirs命令从左到右打印栈中的目录。使用-v选项可以获得更像栈的显示效果:
$ dirs -v 0 /var/tmp 1 ~/part/me/scratch 2 /tmp波浪号~是家目录的简写。可以使用数字重新排列栈,例如pushd +2会将栈中编号为 2 的目录移到栈顶,并切换到该目录,同时将其他目录向下压:
$ pushd +2 /tmp /var/tmp ~/part/me/scratch $ dirs -v 0 /tmp 1 /var/tmp 2 ~/part/me/scratch通过练习这些命令,在多个目录之间反复切换会更加快捷和方便。
8. 重复执行上一条命令
当输入了一条包含长路径名和复杂参数的长命令后,需要再次执行该命令时,有两种方法:
-使用!!:在提示符下输入两个感叹号!!,bash 会回显并重复执行上一条命令。例如:
$ /usr/bin/somewhere/someprog -g -H -yknot -w /tmp/soforthandsoon ... $ !! /usr/bin/somewhere/someprog -g -H -yknot -w /tmp/soforthandsoon ...- 使用箭头键:按下向上箭头键可以滚动查看之前输入的命令,找到想要的命令后,按下回车键即可再次执行。
输入!!时会回显命令,这样可以确认要执行的内容。
9. 执行几乎相同的命令
在执行一条难以输入的长命令后,收到错误消息提示命令行中有一个小拼写错误,此时不需要重新输入整行。可以使用!!命令并添加编辑限定符,类似于sed的替换表达式。例如:
$ /usr/bin/somewhere/someprog -g -H -yknot -w /tmp/soforthandsoon Error: -H not recognized. Did you mean -A? $ !!:s/H/A/ /usr/bin/somewhere/someprog -g -A -yknot -w /tmp/soforthandsoon ...也可以使用箭头键在命令历史中导航,但对于在慢速连接上的长命令,掌握这种语法后会非常方便。不过,使用此功能时要注意替换内容,避免出现意外结果。例如,若尝试通过!!:s/g/h/更改-g选项,可能会导致不必要的更改。
综上所述,这些技巧和方法可以帮助我们在 Unix/Linux 系统的使用中提高效率,减少不必要的操作和错误。通过合理运用这些方法,可以更轻松地完成系统管理和日常操作任务。
Unix/Linux 系统管理与操作效率提升技巧
技巧总结与应用场景分析
为了更清晰地展示上述技巧的应用场景和使用方法,下面通过表格进行总结:
| 技巧名称 | 应用场景 | 使用方法 |
| — | — | — |
| 进程搜索与正则表达式匹配 | 查找特定进程 | 使用ps和grep结合正则表达式,注意不同系统ps命令差异,保证表达式特异性 |
| 为输出添加前缀或后缀 | 收集多台机器统计信息,方便后续处理 | 使用while read循环、awk、Perl或sed实现 |
| 为文本文件的行编号 | 需要参考文本行号 | 可使用while循环、cat、less、vi、nl、awk或perl等方法 |
| 生成数字序列 | 测试或其他需要数字序列的场景 | 使用awk、bash 的算术整数for循环或花括号扩展 |
| 模拟 DOS Pause 命令 | 从 DOS/Windows 迁移过来,需要暂停功能 | 定义pause函数,使用read -p实现 |
| 为长数字添加千位分隔符 | 格式化长数字 | 使用printf、shell 函数或 Perl 函数 |
| 快速在任意目录间切换 | 频繁在多个目录间切换 | 使用pushd和popd管理目录栈 |
| 重复执行上一条命令 | 再次执行长命令 | 使用!!或箭头键 |
| 执行几乎相同的命令 | 修正长命令中的小错误 | 使用!!:s/old/new/进行替换 |
技巧使用流程示例
下面通过 mermaid 流程图展示几个常见技巧的使用流程。
为输出添加前缀的流程
graph TD; A[执行 last 命令] --> B[通过管道传递输出]; B --> C{选择处理方式}; C -->|while read 循环| D[去除空行]; C -->|awk 命令| E[设置输出格式]; D --> F[添加前缀并输出]; E --> F; F --> G{是否保存到文件}; G -->|是| H[重定向到文件]; G -->|否| I[直接输出显示];快速在目录间切换的流程
graph TD; A[进入初始目录] --> B[使用 pushd 切换到新目录]; B --> C[执行操作]; C --> D{是否需要返回上一目录}; D -->|是| E[使用 popd 返回]; D -->|否| F{是否要再次切换}; F -->|是| B; F -->|否| G[结束操作]; E --> C;实际案例分析
假设我们需要从多台服务器收集用户登录信息,并对这些信息进行整理和分析。可以按照以下步骤操作:
1.收集信息:在每台服务器上使用last命令获取用户登录信息,并为输出添加主机名前缀,保存到日志文件。
last | while read i; do [[ -n "$i" ]] && printf "%b" "$HOSTNAME\t$i\n"; done > last_$HOSTNAME.log- 汇总信息:将所有服务器的日志文件收集到一台分析服务器上。
- 分析信息:使用各种工具对汇总后的日志文件进行分析,例如使用
grep查找特定用户的登录记录。
总结与建议
通过掌握上述 Unix/Linux 系统管理与操作技巧,可以显著提高工作效率,减少手动输入的错误和时间成本。在实际使用中,建议根据具体场景选择合适的技巧,同时要注意不同系统之间的差异,进行充分的测试。对于复杂的操作,可以结合多个技巧来完成,例如在分析日志文件时,可以先使用grep筛选出需要的信息,再为输出添加前缀以便后续处理。不断练习和熟悉这些技巧,能够让你在 Unix/Linux 系统管理中更加得心应手。
希望这些技巧能够对你的工作有所帮助,让你在 Unix/Linux 系统的使用中更加高效、便捷。