Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1738611
  • 博文数量: 410
  • 博客积分: 9563
  • 博客等级: 中将
  • 技术积分: 4517
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-03 19:59
个人简介

文章分类

全部博文(410)

文章存档

2017年(6)

2016年(1)

2015年(3)

2014年(4)

2013年(32)

2012年(45)

2011年(179)

2010年(140)

分类: LINUX

2010-07-09 17:24:26

Pixel, Byte, and Comma的软件开发者Martin Streicher 在本文中为我们揭示了UNIX高手的秘密。Martin Streicher 是一位 Ruby on Rails 的自由开发人员和 Linux Magazine 的前任主编。Martin 毕业于 Purdue University 并获得计算机科学学位,从 1986 年起他一直从事 UNIX 类系统的编程工作。他喜欢收集艺术品和玩具。 

保存环境变量

大多数 UNIX 用户在 .bashrc(针对 Bash shell)和 .zshrc(针对 Z shell)等 shell 启动文件中塞满大量用户设置,以便一次又一次地重建钟爱的 shell 环境。启动文件能够创建别名、设置 shell 选项、创建函数、以及设置环境变量。关键的环境变量包括 HOME(指向您的主目录)、PATH(列举从中搜索应用程序的目录)和 MANPATH(列举从中搜索手册页的目录)。要查看您的 shell 中设置了哪些环境变量,键入 printenv 命令。查阅 shell 手册页,获取可用环境变量的完整列表。

与 shell 一样,可以通过环境变量定制其他许多 UNIX 应用程序。例如,Java 子系统要求定义 JAVA_HOME 来指向 Java 运行时的根。同样,Amazon Web Services (AWS) 实用程序套件强制使用 AWS_CREDENTIAL_FILE 来指向一个包含有效私匙凭证的文件。单独的应用程序也提供环境变量,关键是如何发现这些变量。幸运的是,这种工作不需要非法入侵;相反,只需查询手边的实 用工具手册页,查找标题为 “Environment Variables” 的章节即可。

例如,分页实用程序 less 定义了几个有用的环境变量:

◆环境变量 LESS 存储一些命令行选项,以在您每次调用该分页程序时减少键入量。例如,如果您需要阅读大量日志文件,可将以下语句添加到一个 shell 启动文件中:

export LESS='--RAW-CONTROL-CHARACTERS --squeeze-lines --ignore-case'

上述选项将分别解译控制字符(通常是语法着色),将多个空行压缩为一行,并忽略字符串匹配中的大小写。如果您使用代码,可尝试以下选项:

export LESS='--LINE-NUMBERS --quit-if-one-screen --quit-on-intr'

◆名为 LESSKEY 的环境设置指向一个密匙绑定文件。可以使用密匙绑定来定制 less 的行为,比如,匹配另一个页面或编辑器的行为。

◆与 shell 一样,less 能保留多个调用之间的历史。设置 LESSHISTFILE 和 LESSHISTSIZE 分别指向一个持久命令文件和设置要记录的命令的最大条数。

GNU Compiler Collection (GCC) 是另一个典型的环境变量应用示例。GCC 定义各种环境变量来定制其操作。LIBRARY_PATH,顾名思义,是一个目录列表,用于搜索要链接到的库;COMPILER_PATH 的工作方式与 shell 的 PATH 非常相似,但是由 GCC 在内部使用,用于查找编译过程中使用的子程序。

如果您针对单个平台写代码并构建二进制文件,您可能永远也不会用到这些环境变量,但是,如果您跨平台交叉编译相同的代码,那么这些变量对于访问每个 平台的不同的头部和库至关重要。您可以将这些变量设置为不同的值集合,一个集合针对一种机器,而另一个集合针对另一种风格的系统。

事实上,您可以从 GCC 获得一个暗示:可以为每个应用程序维护多个环境变量集合,根据手边的工作从一个集合切换到另一个集合。一种方法是在每个项目目录中保存一个环境初始化文件并根据需要 source 它。例如,许多 Ruby 开发人员使用这种方法来在不同的 Ruby 版本间切换,根据需要更改环境变量 PATH、GEM_HOME 和 GEM_PATH,从一个版本跳到另一个版本。

“点缀” 环境

与环境变量非常相似的是,许多 Linux和 UNIX 应用程序都提供一个 文件 — 文件名以圆点开始的小文件 — 来进行定制。与环境变量不同的是:环境变量采集少量标记和相对较少的信息量,而点文件可能更广泛、更复杂,拥有自己独特的语法规则、甚至自己的编程语言。 点文件是保存选项和设置的理想位置,因为(根据 UNIX 传统)以一个圆点开始的文件名不会出现在标准的目录清单中。(使用 ls -a 来查看这些所谓的隐藏文件。)点文件是纯文本文件,只是文件名比较特别而已。

点文件通常位于您的主目录内,但有些实用程序也在当前工作目录中查找点文件。如果一个应用程序支持多个点文件,则该程序通常应用于优先规则,来表明 一个文件比另一个文件优先。通常,“本地” 点文件 — 位于当前工作目录 — 优先级最高,然后是主目录中的点文件,最后是一个系统范围配置文件。这些文件可以全部存在,也可以存在一个,或者都不存在,这取决于应用程序将这些文件视 为互斥的还是递增的。在第一种情况下,优先链中第一个点文件的优先权是不容置疑的。在后一种情况下,配置可以级联或融解到最终结果中。

less 的密匙绑定文件是一个简单点文件示例,位于 $HOME/.lesskey 中。文件中的每一行都是一对(一个按键和一条命令),如下所示:

\r        forw-line
\n forw-line
e forw-line
j forw-line
^E forw-line
^N forw-line
k back-line
y back-line
^Y back-line

fetchmail 是比较复杂的点文件示例。这个实用程序在本地从多个远程源提取电子邮件并传送消息。这个实用程序的操作只通过 $HOME/.fetchmailrc 控制。(参见手册页了解它的众多选项。)crongitvi,以及其他许多命令都能识别点文件。同样,请阅读这个应用程序的手册页,了解可以在点文件中配置的内容。有些点文件内容丰富,足以占用一个单独的手册页,比如 crontab

嘘......关于 SSH 的秘密

Secure Shell (SSH) 是一个功能强大的子系统,用于安全地登录到远程系统、复制文件并穿越防火墙。由于 SSH 是一个子系统,它提供大量选项来定制和简化其操作。事实上,SSH 提供名为 $HOME/.ssh 的整个 “点目录” 来包含其所有数据。(您的 .ssh 目录必须是模式 600,以阻止他人访问。非 600 模式将干扰正常的操作。)特别是,文件 $HOME/.ssh/config 可以定义大量快捷方式,包括机器名称的别名、每主机访问控制等。

下面是位于 $HOME/.ssh/config 中的一个典型代码块,用于定制一个特定主机的 SSH:

Host worker
HostName worker.example.com
IdentityFile ~/.ssh/id_rsa_worker
User joeuser

~/.ssh/config 中的每个块配置一个或多个主机。不同的块使用一个空行分隔。这个块使用 4 个选项:HostHostNameIdentityFileUserHostHostName 指定的机器创建一个昵称。昵称允许您键入 ssh worker,而不是 ssh worker.example.com。另外,IdentityFileUser 选项指定如何登录到 worker。前者指向此主机使用的一个私匙,后者提供登录 ID。这样,这个代码块就等同于以下命令:

ssh joeuser@worker.example.com -i ~/.ssh/id_rsa_worker

ControlMaster 是一个鲜为人知的强大选项。如果设置,同一个主机的多个 SSH 会话将共享单个连接。一旦第一个连接建立,后续连接就不再需要凭证,从而消除了每次连接同一机器都需要键入密码的麻烦。ControlMaster 非常方便,您可能愿意为每台机器启用它。启用方法非常简单,只需使用主机通配符 *

Host *
ControlMaster auto
ControlPath ~/.ssh/master-%r@%h:%p

如您所料,标记了 Host * 的块将应用到每个主机,甚至是那些在配置文件中没有明确指定的主机。ControlMaster auto 尝试使用一个现有连接,并在没有发现共享连接时创建一个新连接。ControlPath 指向一个文件,以便持久化一个控制套接字以供共享。%r 用远程登录用户名替换,%h 用目标主机名替换,%p 代替连接使用的端口。(您还可以使用 %l,它使用本地主机名替换。)上述规范使用类似于下面的文件名创建控制套接字:

master-joeuser@worker.example.com:22

当到远程主机的所有连接都被切断时,每个控制套接字都就会被移除。如果您想随时了解连接到了哪些主机,只需键入 ls ~/.ssh 并查看控制套接字的主机名部分(%h)。

SSH 配置文件非常大,它也有自己的手册页。键入 man ssh_config 查看所有可能的选项。这里有一个巧妙的 SSH 技巧:可以通过 SSH 从本地系统进入远程系统。要用到的命令行如下所示:

$ ssh example.com -L 5000:localhost:3306

这条命令的意思是:通过 example.com 进行连接,并在本地机器上的端口 5000 和名为 “localhost” 的机器上的端口 3306(MySQL 服务器端口)之间建立一条通道。由于 localhost 在 example.com 上解释(因为通道已建立),因此 localhost 就是 example.com。由于出站通道 — 以前称为本地转发(local forward)— 已建立,本地客户端能够连接到端口 5000,并与 example.com 上运行的 MySQL 服务器通信。

通道创建的常规形式如下:

$ ssh proxyhost
localport:targethost:targetport

其中,proxyhost 是可以通过 SSH 访问的机器,并且拥有一个到 targethost 的网络连接(不通过 SSH)。localport 是您的本地系统上的一个非特权端口(1024 以上的任一未用端口),targetport 是您要连接到的服务的端口。

前面的命令从您的机器发送出去,到达外部世界。 也可以使用 SSH 发送进来,或者从外部世界连接到您的本地系统。入站通道的常规形式如下:

$ ssh user@proxyhost -R proxyport:targethosttargetport

建立一条入站通道 — 以前称为远程转发 — 时,proxyhosttargethost 的角色将被反转:目标是您的本地机器,代理是远程机器。user 是您在代理上的登录名。以下命令提供了一个具体示例:

$ ssh joe@example.com -R 8080:localhost:80

这条命令的意思是:用户 Joe 连接到 example.com,并将远程端口连接到本地端口 80。这条命令向 example.com 上的用户提供一个通道,以连接到 Joe 的机器上。远程用户能够连接到 8080,以便连接 Joe 机器上的 Web 服务器。

除了分别用于本地和远程转发的 -L-R 之外,SSH 还提供 -D 参数来在远程机器上创建一个 HTTP 代理。请参见 SSH 手册页了解正确语法。

使用历史记录重写

如果您经常在 shell 提示符中花费大量时间,保存 shell 历史记录可以节约时间和输入。但是如果历史记录不能被修改,就会导致一些麻烦:记录重复的命令,且多个 shell 实例可能会干扰各自的历史记录。这两个问题很容易解决,只需在您的 .bashrc 中添加两行:

export HISTCONTROL=ignoreboth
shopt -s histappend

第一行将移除您的 shell 历史记录中连续的重复命令。如果您想移除所有零散的副本,可将 ignoreboth 更改为 erasedups。第二行在 shell 退出时将 shell 的历史记录附加到您的记录文件。默认情况下,Bash 记录文件命名为 ~/~/.bash_history (不错,这是一个点文件)。可以通过设置 HISTFILE(不错,这是一个环境变量)来更改它的位置。如果您想将一个 shell 的最近 10,000 命令保存在一个包含 100,000 条目的记录文件中,将 export HISTSIZE=10000 HISTFILESIZE=100000 添加到您的 shell 启动文件中。要查看一个 shell 的历史记录,在任意提示处键入 history 即可。

如果不能调用,那么保存的命令历史记录就用处不大。而这正是 shell !(或 bang)操作符的作用所在:

  • !! ("bang bang") 完整地重复最后一条命令。
  • !:0 是前一条命令的名称。
  • !^ 是前一条命令的第一个参数。!:2!:3 ... !$ 等命令是前一条命令的第二、第三......以及最后一个参数。
  • !* 是最后一条命令的所有参数,命令名除外。
  • !n 重复历史中编号为 n 的命令。
  • !handle 重复以 handle 中的字符开始的最后一条命令。例如,!ca 将重复以字符 ca 开始的最后一条命令,如 cat README
  • !?handle 重复包含 handle 中的字符组成的字符串的最后一条命令。例如,!?READ 还会匹配 cat README
  • ^original^substitution 使用 substitution 替换 original第一个 实例。例如,如果前一条命令是 cat README,,命令 ^README^license.txt 将生成一条新命令 cat license.txt
  • !:gs/original/substitution 将使用 substitution 替换 original所有 实例(!:gs 表示 “全局替换[global substitution]”)。
  • !-2 是倒数第二条命令,!-3 是倒数第三条命令,以此类推。

您甚至可以合并历史表达式来生成 !-2:0 -R !^ !-3:2 这样的 “魔汤”,该命令将扩展为倒数第二条命令的名称,加上 -R,再加上前一条命令的第一个参数,以及倒数第三条命令的第二个参数。要使这样的神秘命令更具可读性,可以在键入时扩展历史参考。在任意提示符键入命令 bind Space:magic-space ,或者将其添加到一个启动文件,从而将空格键绑定到函数 magic-space,该函数将扩展内联历史替换。

与扩展名无关的自动解压

鉴于 Internet 上有如此众多的代码,您可能每天都会下载数十个文件。可能会出现这样的情况:所有那些文件都使用不同的方式打包 — 有的是 ZIP 文件,有的是 RAR 文件,还有很多是 tarball 文件,尽管每个包都使用不同的实用程序压缩。记住如何解压缩和扩展每种包格式将会使人精疲力尽。那么,为何不在单个命令中完成所有那些任务呢?下面这个函 数在许多样例点文件中广泛可用:

ex () {
if [ -f $1 ] ; then
case $1 in
*.tar.bz2) tar xjf $1 ;;
*.tar.gz) tar xzf $1 ;;
*.bz2) bunzip2 $1 ;;
*.rar) rar x $1 ;;
*.gz) gunzip $1 ;;
*.tar) tar xf $1 ;;
*.tbz2) tar xjf $1 ;;
*.tgz) tar xzf $1 ;;
*.zip) unzip $1 ;;
*.Z) uncompress $1 ;;
*.7z) 7z x $1 ;;
*) echo "'$1' cannot be extracted via extract()" ;;
esac
else
echo "'$1' is not a valid file"
fi
}

这个函数 ex 扩展了 11 种文件格式;如果要处理其他包类型,该函数还可以扩展。一旦定义 — 例如,在一个 shell 启动文件中 — 就可以简单地键入 ex somefile,其中 somefile 以以下一种已命名扩展结束:

$ ls
source
$ tar czf source.tgz source
$ ls -1
source
source.tgz
$ rm -rf source
$ ex source.tgz
$ ls -1
source
source.tgz

顺便说一下,如果您将今天下载的文件放错了位置,可以运行 find 来查找它:

$ find ~ -type f -mtime 0

命令 -type f 查找纯文本文件,-mtime 0 查找自当天午夜以来创建的文件。

更多秘密

需要揭开的专家秘密还有很多。在 Web 上搜索 “shell auto-complete”,进一步了解自动完成特性,该特性用于在您键入一条命令时提供上下文敏感的扩展。另外,搜索 “shell prompts” 以了解如何定制您的 shell 提示:可以将其设置为彩色,可以设置您的当前工作目录或 Git 分支,还可以显示历史数目 — 如果经常调用历史,这是一个方便的参考信息。要查看工作示例,可在 Github 中搜索 “dot files”。许多专家都将他们的 shell 配置张贴在 Github 上。
阅读(947) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~