我的一个朋友刚买了了一台Unix计算机,控制台显示不是非常合适,例如我们查看一个文件时,操作系统不知道屏幕有多大,它显示了整个文件而不是每次一屏。

那时,我的计算机水平也不是很好,但是我记得有一个stty命令可以更改显示的属性,我查看了stty的帮助文档,注意到有两条设置命令rows和line,想当然的认为line应该是行数,于是我输入stty line 24。计算机停止响应,迫使我们重新启动了计算机。

我打电话给一位Unix专家,他有同样的操作系统。他说:“这条命令应该是正确的,让我试一试。”过了一会,他接着说:“我的计算机也挂了”。

结果这条命令是设置用来显示的串口号,把它设置为24,而串口24号没有接显示器,当然屏幕不会有任何显示。基于Unix的操作系统(如Linux)有大量的选项可以设置,有时是很难猜测出它们的实际作用的。本章是对上一章内容的扩充,涵盖了更多的基本命令和容易混淆的选项。

列出文件


命令ls的功能是显示出当前目录中的内容。虽然ls在所有的Unix型操作系统中都是有效的,Linux使用的ls命令来自于GNU fileutils项目而且还有许多得数的开关和特性。

$ls

archive check-orders.sh orders.txt

ls命令开关可以设置如何列出这些文件、显示的细度、排列的顺序和列数。大部分已发行的Linux设置为ls命令的某个缺省配置。例如Red Hat缺省有-q和-F设置。从写脚本的角度来说,使用ls命令而没有设置适当的开关是不安全的,因为你不能确定你的发行版本中是否包含了缺省值。

ls命令不显示以句号开始的文件。通常这些是Linux文件的配置文件、历史文件和其他用户不会使用的文件。如果要显示这些文件需要加上-A开关。使用-a将显示两个固有的文件.和..文件。

$ ls

.bash_history  .bash_logout   .bash_profile   .bashrc    archive    check-orders.sh     orders.txt

文件名可以根据它们的类型以不同的颜色进行显示。颜色的定义在/etc/DIR_COLORS文件中。你可以在自己的目录中使用.dir_colors文件定义自己的颜色。文件的格式和/etc/DIR_COLORS文件中的格式一样。

也可以使用符号而不是颜色进行文件类型的标示,使用—color和—classify(或-F)开关(在大部分Linux发行版中,这个特性使用别名来打开)。

$ ls  --color=nerver       --classify

archive/   check-orders.sh*   orders.txt

-classify符号的描述是目录(/)、程序(*)、符号链接文件(@)、管道(|)、Unix域套接文件(=)。这些符号不是名字的组成部分:它们标示了文件的类型。本例中,archive是一个目录,check-orders.sh是一个程序。

另一个非常有用的开关是—hide-control-chars(或-q)。Linux文件名可以包含任何字符,甚至是控制字符。文件名包含因此字符也是可能的。如果有这种情况,更改文件名或删除文件名是不可以的,除非你知道隐含的文件名是什么。--hide-control-chars开关将控制是否显示文件名中不可以打印的文件名,不可显示的文件名以问号符号进行显示,可以标示出它们的位置。

$ rm orders.txt

rm:orders.txt non-existent

$ ls –color=never –classify –hide-control-chars

archive/   check-orders.sh*   orde?rs.txt

本章的结尾将显示所有的开关。

printf命令


内置的printf命令用于在屏幕上显示一条消息,在外壳脚本程序中会经常使用这条命令。

printf命令类似于C语言中I/O函数printf(),但是它们是不同的。特定在单引号和双引号的使用上是完全不同的。

第一个参数是一串格式字符串,表示了如何显示这些字符串。例如:“%d”表示整数,“%f”表示浮点数。

$ printf    “%d/n”  5

5

$ printf    “%f/n”    5

5.000000

你要打印的每个值包含在格式代码中,格式代码将以合适的形式被变量值所替换掉。格式字符串中非指令格式的字符将会原样打印出来。

$ print “There are %d customers with purchases over %d./n” 50 20000

There are 50 customers with purchases over 20000.

printf命令有时可以将一个变量或不更改输入的值从新定向到命令。例如:将变量通过管道输入到命令中。不使用printf,Bash提供了一个快捷符号”<<<”,来重定向。“<<<”用来将一个字符串重定向到命令中,就像管道一样。

tr命令用来将文本从小写改为大写。本例显示了转换过程中的出错信息。

$ printf    “%s/n” “$ERRMSG” |   tr     [:lower:]  [:upper:]

WARNING:    THE FILES FROM THE OHIO OFFICE HAVEN’T ARRIVERD.

$ tr[:lower:]    [:upper:]

WARNING: THE FILES FROM THE OHIO OFFICE HAVEN’T ARRIVED.

格式代码如下列所示:

n         %a——16进制的浮点数,使用小写字母

n         %A——16进制的浮点数,使用大写字符

n         %b——扩充反斜线符号序列

n         %c——单个字符

n         %e——显示浮点数,以指数形式显示

n         %d——显示一个有符号数

n         %f(或%F)——显示浮点数,不使用指数形式

n         %g——根据显示的值来决定使用%e或%f

n         %i——同%d

n         %o——显示八进制数

n         %q——引用一个字符串以便可以被外壳脚本程序正常读取

n         %s——显示一个非引用字符串

n         %u——显示一个无符号数

n         %x——显示一个无符号的16进制数,使用小写字母

n         %X——显示一个有符号16进制数,使用大写字母

n         %%——显示一个百分号

如果一个数太长,Bash会报告超长的错误提示。

$ printf “%d/n” 123456789123456789012

bash:       printf:      warning:  123456789123456789012:     Numerical result out of range

为了和C语言的printf兼容,Bash也识别下列标志,但是和%d的含义相同:

n         %j——C语言的intmax_t或uintmax_t整数

n         %t——C语言的ptrdiff_t整数

n         %z——C语言的size_t或ssize_t整数

为了C的兼容性,你可以使用l或L来表示长整数。

%q格式在脚本程序中是非常重要的,在第五章“变量”中会详细讨论。

为了有报表的样式,可以指定要显示的信息的宽度。例如:“%10d”显示一个有符号数有10列的宽度。

$printf     “%10d/n”       11

          11

同样可以设定显示的列为左对齐。

$printf     ”%-10d %-10d/n”  11 12

11          12

带有小数点的数表示要显示的数的长度和最小的精确度。例如:“%10.5f”表示一个浮点数的长度为10个字符,小数点的精度为5位。

$     printf      “%10.5f/n”     17.2

       17.20000

最后,撇号用来显示当前国家的千分位数。

“/n”格式字符串是一个用反斜杠开头的格式字符表示是不可显示的字符。“/n”表示换行。反斜杠开头的格式字符用来表示不可以显示的字符。

n         /b——退格

n         /f——换页

n         /n——换行

n         /r——回车

n         /t——制表符

n         /v——垂直制表符

n         /`——单引号字符(兼容C)

n         //——退格

n         /0n——n是一个八进制数表示一个8bit的ASCII字符

$     printf      “Two separate/nlines/n”

Two separate

lines

printf命令将0开头的数认作8进制数据,0x开头的数据认作16进制数据。他还能在不同进制的数据进行转换。

$     printf      “%d/n”    010

8

$     printf      “%d/n”    0xF

15

$     printf      “0x%x/n”       15

0xF

$     printf      “0%o/n” 8

010

大部分发行的Linux都有独立的printf命令用来和POSIX标准进行兼容。

获取帮助


Bash外壳命令有一个内置的help命令用来描述不同的内置Bash命令。“-s”开关用来显示你指定的命令的概述。

$help –s printf

printf:      printf format [arguments]

help命令只显示Bash命令。为了获取Linux命令的帮助,你需要使用man(manual)命令。

$man date

Linux系统把手册页按照逻辑卷进行划分。man 显示所有卷中和命令相匹配的内容。卷1包含了外壳脚本可以执行的内容。为了限制帮助名字在外壳脚本中使用命令man 1。

$ man 1 date

如果你要找的内容在不止一卷手册中,只显示第一卷的内容,要想显示所有卷的内容,你需要使用“-a”的开关。

“-k”开关用来在Linux手册中查找特定的关键词并列出引用到这个关键词的手册页。

$     man 1     -k    alias

help type命令给你和man 1 type命令不同的信息。help type命令告诉你关于Bash内置命令type的信息。而man 1 type会告诉你关于Linux命令type的信息。如果你不能确定该命令是否为Bash命令,可以在使用man命令之前试一下help命令。

修正显示


有时,Bash会话会变得不稳定。每个字符队列不能锁定你的显示,你打印出来的字符不能显示或显示为很奇怪的字符。例如:你尝试显示一个二进制字符,会发生这种情况。

命令reset会尝试恢复Bash会话到一个安全和正常的状态。

如果reset命令失败,你可以使用stty sane来恢复会话到一个正常的状态。

命令clear清除显示并恢复光标到屏幕的左上角。

对文件的操作


Linux有几个命令可以删除、拷贝和移动文件。

mkdir(make directory)建立一个新的目录。使用mkdir来管理你的文件。

$ mkdir   prototypes

$ ls  -l

total 4

drwxr –xr-x    2     ken  users       4096       Jan  24    12:50      prototypes

mkdir命令有两个开关

n         --mode=m(-m)——设置允许模式(就像使用chmod)

n         --parents (-p)——即使这些目录不存在也建立所有必要的目录

$mkdir    --parents --mode=550    read_only/backup/january

$ls –l

total 4

drwxr-xr-x   2 ken      users        4096 Jan 24 12:50 backup

drwxr-xr-x   3 ken      users        4096 Jan 24 12:51 read_only

$ ls -l read_only/backup

total 4

dr-xr-x---   2 ken      users        4096 Jan 24 12:51 january

mode的值将在“第15章 外壳脚本的安全”中的chmod命令进行讨论,可是当使用—parents开关,--mode只对列表中的最后一个目录有影响。

命令rmdir(remove directory)删除一个目录。这个目录必须是空的。它有两个开关:

n         --ignore-fail-on-non-empty——当删除的目录中有文件时,不不报告错误。

n         --parents(-p)——删除所有的父目录及子目录。

$ rmdir read_only

rmdir: read_only: Directory not empty

$ rmdir --parents read_only/backup/january/

rm 命令永久性删除文件。如果文件是一个符号或硬链接文件,它删除链接而不是文件本身。

$ rm old_notes.txt

$ ls old_notes.txt

ls: old_notes.txt: No such file or directory

rm命令有几个开关:

n         --directory(-d)——删除目录

n         --force(-f)——不提示用户并忽略不存在的文件

n         --interactive(-i)——总是提示用户

n         --recursive(-r或-R)——删除所有子目录中的内容

同时使用—recursive和—force开关将删除所有包含的文件和子目录,并不会有警告信息。你需要自己确保删除文件的正确性。

有些Linux的发行版使用—interactive开关作为缺省值,因此rm命令将会得到你的确认后才会删除指定的文件。

$ rm --interactive old_notes.txt

rm: remove ‘old_notes.txt’? y

$

通常rm不会删除目录但是使用了—recursive开关,它将删除任何包含的目录。

cp命令将文件从一个地方拷贝到另一个地方。如果参数文件最后列出的是一个目录。copy命令将所有的文件拷贝到这个目录。

有许多copy的开关——本章的结尾有完整的引用列表。一些通用的开关如下所示:

n         --force(-f)——不提示用户;总是覆盖

n         --interactive(-i)——总是提示用户

n         --link(-l)——建立硬连接而不是拷贝

n         --parents(-P)——增加源路径到目标路径

n         --recursive(-R)——拷贝任何子目录

n         --symbolic-link(-s)——建立符号链接文件而不是拷贝

n         --update(-u)——覆盖旧文件或拷贝不存在的文件

$ cp notes.txt old_notes.txt # copying

$ mkdir backup

$ cp old_notes.txt backup

$ ls backup

old_notes.txt

和rm命令一样,有些Linux发行版中的copy命令缺省有—interactive开关,提示文件将会被覆盖。

$ cp --interactive project_notes.txt old_notes

cp: overwrite ‘old_notes/project_notes.txt’? n

$

mv(move)命令用来移动文件或更改文件名。象copy命令一样先将文件拷贝到另一个地方,但是mv命令会删除原始文件。mv命令也可以用来在相同目录中的文件进行改名。

$ mv notes.txt project_notes.txt # renaming

mv通用的开关如下所示:

n         --backup(-b)——在覆盖现存的文件时会将现存的文件名加一个~字符,来备份现存的文件。

n         --force(-f)——不提示用户;总是覆盖

n         --interactive(-i)——覆盖前总是提示用户

n         --update(-u)——覆盖旧的文件或拷贝不存在的文件

没有—recursive开关,当使用move命令移动一个目录时,它自动移动目录和目录所包含的内容。

namei(name inode)命令列出一个路径中所有的成分,包含符号连接。

$ namei files

f: files

l files -> /home/ken/bash/scripts

d /

d home

d ken

d bash

d scripts

本例中文件名files是一个符号链接。在这个链接路径中的每一个目录使用字符d进行标识,字符设备使用字符c进行标识,符号链接文件使用字符l进行标识,socket文件使用字符s进行标识,块设备使用b进行标识,常规文件使用字符-进行标识,?表示在路径中访问一个文件出错。

完整的文件许可模式可以使用-m(mode)开关显示,也可以使用ls –l看到。

对用户的操作


有几个命令可以查看谁登陆到计算机上了,他们在做什么?

finger命令显示显示了谁在计算机上,并提供了一些其他信息,包括他们的会话已经空闲了多长信息已经他们的联系信息。

$ finger

Login       Name               TTY Idle    When    Bldg.         Phone

dhu      Dick Hu              *p6  4:25 Thu 14:12  4th Floor     ext 2214

mchung   Michael Chung        *con 5:07 Fri 09:57  OS Support    ext 1101

bgill    Biringer Gill        *p7   15  Fri 13:32

基于安全的考虑(访问finger’s.plan文件的权限),一些Linux版本不再包含finger命令。阅读finger手册页可以获取更多的信息。

还有一些其他的命令有类似的功能。users命令显示了一份登陆名的列表。

$ users

bgill dhu mchung

who命令显示了谁在计算机上,他们使用的连接是什么,它们在哪里登陆的。

$ who

dhu        ttyp6        Mar 29 14:12

mchung     console      Apr  6 09:57

bgill      ttyp7        Apr  6 13:32

w命令提供了更多的信息,包含系统状态统计和用户当前正在使用什么程序。

$ w

3:18pm  up 9 days, 20:33,  3 users,  load average: 0.64, 0.66, 0.64

User     tty           login@  idle   JCPU   PCPU  what

dhu      ttyp6         2:12pm  4:28   8:01   8:01  csh

mchung   console       9:57am  5:10                sh

bgill    ttyp7         1:32pm    19                bash

外壳脚本命令的别名


alias是命令的短格式。内置命令alias建立了当前Bash会话的缩写。为了建立一个别名,使用alias命令将一个命令和它的开关分配给一串字符。

$ alias lf=’ls -qFl’

$ lf

-rw-r-----   1 kburtch    devgroup     10809 Apr  6 11:00 assets.txt

-rw-r-----   1 kburtch    devgroup      4713 Mar  9  2000 mailing_list.txt

打印alias命令本身或加上“-p”开关,列出当前的使用别名的命令

$ alias

alias lf=’ls -qFl’

Bash只解释别名一次,别名允许使用命令本身作为别名。

$ alias ls=’ls -qF’  # Bash isn’t confused

通常只检查命令的第一个单词是否为别名,如果,上一个字符是空格,Bash也检查命令中的下一个单词是否也是别名。

使用别名后就不可以使用参数了,如果要使用参数,需要更强大的脚本命令。

内置命令unalias可以删除一个别名,开关“-a”则删除所有的别名。

大部分发行的Linux版本都使用别名定义一些通用的命令。例如:dir通常是ls的别名。还有一些命令给rm –i定义别名,迫使用户删除文件时进行提示。但是一些有经验的Unix程序员在使用这些命令时可能引起混乱,他们通常关闭这些功能。使用unalias命令删除它们不想要的别名。

和外壳脚本一起使用别名可能会导致混乱,因为别名只在脚本被按行读取时才进行扩展。如果别名使用在脚本函数中,脚本函数在定义时就进行扩展,而不是等到它们执行时。因此,最好不要在外壳脚本中使用别名。可是,你也可以在脚本中使用shopt –s expand_aliased命令打开别名的使用。

Bash的哈希表


当执行一个命令而没有指定路径时,外壳程序查找这个命令(在PATH变量中指定的目录)。找到这个命令之后,外壳程序将命令的位置保存在hash table(哈希表)中。之后,再次运行此命令时,Bash在表中查找命令的位置而不是再次搜索此命令,从而更快的执行命令。可是,当Bash记录了命令的位置之后,命令的位置被移动了,外壳就找不到这个命令了。

内置hash命令维护着哈希表。不使用任何开关,hash列出内存中的命令、它们的位置、会话期命令执行的次数。

$ hash

hits    command

1    /bin/ls

1    /bin/uname

1    /usr/bin/tput

1    /bin/stty

1    /usr/bin/uptime

1    /usr/bin/man

如果后面跟了一个命令,Bash会查找这个命令的新位置。例如,你创建了一个命令ls,保存在当前的目录,PATH变量设定了当前目录优先使用,hash ls命令首先找到你自己建立的ls命令,使用./ls替代/bin/ls。

$ hash ls

$ hash

hits    command

1    /bin/touch

0    ./ls

1    /bin/chmod

“-p”(path)开关显示的设定命令的路径。“-d”(delete)开关删除某个条目,“-r”(remove)清除hash表,删除所有的命令。“-t”(table)开关列出指定命令的路径。“-l”(list)以某种格式列出命令使hash命令可以重新使用它们。

$ hash -t ls less

ls      /bin/ls

less    /usr/bin/less

自定义提示符


虽然一些发行版使用不同的符号,但是缺省的Bash提示符是一个美元符号($)。大部分Linux的发行版重新定义提示符,以便可以包含一些额外的信息,例如你的登陆名和计算机名,当你在不同的计算机上使用不同的账户时,这是非常有用的。

如果PS1(prompt string 1)的变量名已经定义了,Bash将使用这个值作为你的提示符。如果你在这个字符串包含了变量名,Bash将使用变量替换你的提示符。

$ declare -x PS1=”Bash $ “

Bash $ pwd

/home/kburtch/archive

Bash $

下面命令声明了声明了一个三行的提示符,其中包含了一个空行、当前目录、先前的当前目录和登录名和计算机名,还有一个粗体的$.

$ declare -x PS1=”

/$PWD (/$OLDPWD)

/$LOGNAME@’uname -n’/[‘tput bold’/] /$ /[‘tput rmso’/]”

/home/kburtch/archive (/home/kburtch/work)

kburtch@linux_box $

/[和/]将显示格式字符括起来,格式字符通过tput命令返回。否则,Bash认为所有的字符都是显示的,而不能正确的区分这串长字符串。

Bash还有PS2变量,它是对多行未结束的命令的提示符,例如使用了多行的引用。缺省情况下,它是一个大于号“>”。

Bash在提示符中识别下列换吗字符:

n         /a——A beep(ASCII钟的字符)

n         /A——24小时的时间格式HH:MM

n         /d——时间格式“星期-月-日”

n         /D[s]——使用格式字符串s运行C语言的statftime函数

n         /e——ASCII的退出字符

n         /h——主机名

n         /H——完整的主机名包含域名

n         /j——在作业表中的作业号

n         /l——tty设备

n         /n——新行

n         /r——回车

n         /s——外壳名

n         /t——24小时格式的时间

n         /T——12小时格式的时间

n         /@——AM/PM格式的时间

n         /u——用户名

n         /v——Bash的版本

n         /w——当前的工作目录

n         /W——当前工作目录的基本名

n         /!——命令历史表的正向命令

n         /#——会话的序列命令号

n         /$——缺省提示符(超级用户使用#,否则使用$)

n         /nnn——ASCII字符的八进制格式

n         //——A斜杠

n         /[——不可显示字符的开始

n         /]——不可显示字符的结束

第五章将会详细讨论变量。你可以使用peomptvars外壳选项来关闭变量替换。

长命令行


如果命令过长,Bash自动滚动屏幕,例如:输入命令时光标到了窗口的右边,Bash自动切换到下一行。

如果你想将一个命令分成多行显示,你需要在一行的结尾使用斜杠(/)。Bash会在下一行显示提示符,通常是一个“>”,表示先前的行还没有结束。

$ printf “%s/n” “This is a very long printf.  How long is it?/

> It’s so long that I continued it on the next line.”

This is a very long printf.  How long is it? It’s so long that I continued it on

the next line.

自定义命令行的编辑


bind命令使你可以更改编辑键、编辑选项、以及建立键盘宏命令。更改只影响当前的编辑模式。

“-p”和“-P”开关显示了不同命令行的编辑功能——激活不同的键盘组合。“-P”以容易阅读的方式进行显示。

$ shopt -o emacs

emacs           on

$ bind -P | head -5

abort can be found on “/C-g”, “/C-x/C-g”, “/e/C-g”.

accept-line can be found on “/C-j”, “/C-m”.

alias-expand-line is not bound to any keys

arrow-key-prefix is not bound to any keys

$ shopt -s -o vi

$ bind -P | head -5

abort is not bound to any keys

accept-line can be found on “/C-j”, “/C-m”.

alias-expand-line is not bound to any keys

arrow-key-prefix is not bound to any keys

使用“-m”(keymap)开关可以设定特定的编辑模式。

$ bind -P -m vi | head -5

abort can be found on “/C-g”.

accept-line can be found on “/C-j”, “/C-m”.

alias-expand-line is not bound to any keys

arrow-key-prefix is not bound to any keys

特殊字符可以使用斜杠“/”来表示。这些特殊字符是有emacs文本编辑器器所使用的。

n         //——一个斜杠

n         /”——一个双引号

n         /’——一个单引号

n         /a——一个报警(bell)

n         /b——后退一格

n         /c——Ctrl键

n         /d——删除

n         /e——退出键

n         /f——换页

n         /M——emacs的meta键

n         /n——换行键

n         /r——回车键

n         /t——水平tab键

n         /v——垂直tab键

n         /nnn——八进制的ASCII码

n         /xnnn——16进制的ASCII码

例如:control-g由/C-g来表示。

“-l”(list)开关列出所有可能的键盘功能。

$ bind -l | head -5

abort

accept-line

alias-expand-line

arrow-key-prefix

backward-char

为了看到某个特定的功能使用“-q”(query)开关。

$ shopt -s -o emacs

$ bind -q abort

abort can be invoked via “/C-g”, “/C-x/C-g”, “/e/C-g”.

使用“-u”开关可以删除某个绑定。如果由不止一个绑定,只删除第一个。

$ bind -u abort

$ bind -q abort

abort can be invoked via “/C-x/C-g”, “/e/C-g”

“-r”(remove)可以删除指定的绑定。

$ bind -r “/e/C-g”

$ bind -q abort

abort can be invoked via “/C-x/C-g”.

你也可以使用组合键、冒号和编辑功能名来增加一个新的绑定。例如:backward-kill-line功能用来删除从行的开始到光标所在位置的所有字符。在vi模式,backward-kill-line通常并没有绑定到任何组合键上。

$ shopt -s -o vi

$ bind -q backward-kill-line

backward-kill-line is not bound to any keys.

下面示范了如何将backward-kill-line功能绑定到一个组合键上。

$ bind “/C-w:backward-kill-line”

$ bind -q backward-kill-line

backward-kill-line can be invoked via “/C-w”.

现在control-w可以从行的开始处删除字符了。

除了上面的功能外,还有一些选项或变量。“-v”和“-V”开关显示这些键盘设置的选项。“-V”选项以更容易理解的方式显示。

$ bind -v | head -5

set blink-matching-paren on

set completion-ignore-case off

set convert-meta on

set disable-completion off

set enable-keypad off

$ bind -V | head -5

blink-matching-paren is set to ‘on’

completion-ignore-case is set to ‘off’

convert-meta is set to ‘on’

disable-completion is set to ‘off’

enable-keypad is set to ‘off’

这些选项可以打开或关闭,如下所示:

$ bind “set enable-keypad on”

$ bind -V | head -5

blink-matching-paren is set to ‘on’

completion-ignore-case is set to ‘off’

convert-meta is set to ‘on’

disable-completion is set to ‘off’

enable-keypad is set to ‘on’

所有有效的功能和选项的列表参考Readline手册页的内容。

bind命令也可以定义键盘宏命令。将一些长命令定义为短的组合键,从而减少输入量。“-s”和“-S”开关列出当前定义的宏命令。“-V”开关是更人性化的阅读方式。

建立宏命令的格式和分配功能的格式一样,除了“/””必须包含要扩展的文本。

$ bind -S

$ bind “/C-w:/” >/dev/null/””

$ bind -S

/C-w outputs  >/dev/null

Control-w将插入“>dev/null”到当前行。

你自己的会话配置文件


当你登陆到一台计算机上并开始一个新的会话,你也许需要输入几个命令来配置你的会话环境。也许你想将编辑环境从emacs改为vi、建立新的键绑定或更改你的命令提示符。如果你将这些配置保存在一个特定的文件,Bash将在你每次登陆是运行这些命令,而不是你每次自己输入这些命令。这些文件称之为profile file,它包含你自己定义的命令来适合你的会话。

最初的Bourne外壳在用户登陆时运行两个配置文件。第一个称之为“/etc/profile”,它是一个通用的配置文件,适合所有的用户。第二个是“.profile”,他保存在用户的主目录中,可以包含每个用户特定的配置信息。Bash开始于sh时模仿了这种行为。

Bash扩展了运行几个依赖于环境的配置文件的原则,此外,Linux发行版经常自定了配置文件来运行保存在其他脚本中的命令。

Bash能区分登陆会话和其他实例。当用户或程序首先登陆或使用Bash的“—login”来模拟登陆时,Bash作为登陆外壳运行。一个登陆外壳并不须给用户提供一个提示符。它只表示Bash在当前会话中是一个上面的程序,当Bash运行完,登陆会话也结束了。

当你在登陆外壳中,login_shell外壳选项打开。这个选项用于验证你是否在登陆外壳中。

$ shopt login_shell

login_shell     on

当Bash开始时没有使用脚本或使用了-i开关,Bash作为interactive shell(交互外壳程序)来运行。交互外壳给用户提供了提示符。交互外壳程序不必是登陆外壳程序。用户可以通过在Bash提示符下打印Bash来运行一个非登陆的交互外壳程序。使用这种方法,Bash将命令从更多通用目的的命令中分离出用于自定义交互会话的命令。

“/etc/profile”文件包含了设置命令,适用于所有用户的环境。通用的配置文件跟下面的示例文件差不多:

#!/etc/profile

# No core files by default

ulimit -S -c 0 > /dev/null 2>&1

# HOSTNAME is the result of running the hostname command

declare –x HOSTNAME=`/bin/hostname`

# No more than 1000 lines of Bash command history

declare –x HISTSIZE=1000

# If PostgreSQL is installed, add the Postgres commands

# to the user’s PATH

If test –r /usr/bin/pgsql/bin ; then

declare –x PATH=”$PATH””:/usr/bin/pgsql/bin”

fi

# end of general profile

只有超级用户可以编辑这个文件。当Bash用作登陆外壳时,他执行的第一个文件可以叫做“~/.bash_profile”,“~/.bash_login”,“~/.profile”。当会话完成,如果有“~/.bash_logout”文件,Bash运行它。

例如:SuSE Linux运行“~/.profile”作为用户的配置文件。你可以查看你的主目录是否有这个文件。通过编辑这个文件,你可以增加你想在登陆时执行的命令。

# My profile

shopt -s -o emacs   # I prefer emacs mode to vi mode

date                # display the date when I log on

通过使用“-login”开关来模拟登陆并测试上面的更改。

$ bash --login

Wed Feb  6 15:20:35 EST 2002

$ shopt -o emacs

emacs           on

$ logout

不登陆而运行一个新的Bash交互会话,系统将不会运行配置文件。

$ bash

$ logout

bash: logout: not login shell: use ‘exit’

$ exit

如果配置文件脚本不能正常运行,系统叫从BASH_ENV环境变量查找相应的脚本进行执行,BASH_ENV通常包含了要执行的文件和路径。可是,你应尽量避免使用BASH_ENV变量。给一组脚本设置通用环境通常使用source命令来完成,此命令在第14章进行讨论。BASH_ENV在交互会话中没有效果。

你可以通过使用“—noprofile”开关来停止登陆脚本的运行。Bash在交互会话中运行不同的配置文件,在外壳会话中也适用不同的配置文件。Bash在文件“~/.bashrc”中寻找自定义脚本并执行它们,而不是使用登陆配置文件。别名功能只允许使用在资源文件中。一个不同的资源文件可以使用“—init-file”或“—rcfile”开关来指定。典型的资源文件如下所示:

# /etc/bashrc

# Don’t let others write to the user’s files

umask 002

# Alias ls to provide default switches

alias ls=’ls –qF’

一些发行版增加了几行代码到你的登陆配置文件中,它们用来运行“~/.bashrc”文件中的命令。这不是Bash的特性,而是Linux发行版所做的更改。你可以增加下面几行代码来测试“~/.bashrc”是否运行了。

# My bashrc Resource File Customizations

printf “%s/n” “.bashrc has run”

在命令提示符下开始一个新的会话来测试上面的代码。SuSE Linux的运行结果总是如下所示:

$ bash --login

.bashrc has run

$ logout

$ bash

.bashrc has run

$ exit

最终,你只有通过测试你自己的Linux发行版才能知道是否包含了资源文件。

资源文件可以使用“--norc”开关来禁止运行。

某些发行版还可以在登陆时运行其他的文件:

n         Red Hat和Mandrake Linux将你的自定义、功能和别名分开放在“~/.bashrc”,而其他的设置放在“~/.bash_profile”文件中。后面的文件将自动运行前面的文件(如果前面的文件存在的话)。

n         SuSE Linux将你的自定义、功能和别名分开存在“~/.bashrc”文件中,其他的自定义保存在“~/.profile”文件中。后面的文件自动调用前面的文件(如果前面的文件存在的话)。

n         SCO Linux(也称之为Caldera Linux)使用“~/.profile”,它调用“~/.bashrc”文件。它接着运行“/etc/config.d/shells”来配置系统的缺省值。当“~/.bashrc”运行时,它调用“/etc/config.d/shells/bashrc”来设置非交互的缺省值。用户的自定义保存在“~/.profile-private”和“~/.bashrc-private”文件中。

同样,通用配置文件也可以自定:

n         Red Hat和Mandrake也将自定义分为“/etc/bashrc”和“/etc/profile”来模仿用户配置文件的行为。

n         SuSE Linux自动设置“/etc”中的多个文件中内容,包含“/etc/profile”。最终,用户更改必须保存在分开的文件称之为“/etc/profile.local”,当系统升级或重新配置时,这些配置会丢失的。其他的系统脚本自动执行“/etc/SuSEconfig”文件,已安装的软件包保存在“/etc/profile.d”的脚本文件中。SuSE也包含了“/etc/profile.dos”脚本用来定义来自MS-DOS系统的用户。这些通过SuSE的配置软件来设定,但是他也可以从“/etc/profile.local”文件中执行。

n         SCO Linux只在“/etc/profile”文件中放置最小的和最通用的设置信息来设定Bourne-based脚本。通用的Bash设置保存在“/etc/config.d/shells/profile”和“/etc/config.d/shells/bashrc”文件中。保存在“/etc/profile.d”文件中的脚本是为了自动执行系统已安装的软件包。

命令参考


ls命令的开关


n         --all(or –a)——显示所有的文件包含“.”和“..”。

n         --almost-all(或者-A)——除了“.”和“..”两个文件显示所有的文件

n         --block-size=n——以n字节为单位来显示文件的大小

n         --classify(或者-F)——显示文件名时增加一个符号来表示它的类型

n         --color=t——使用颜色来表示文件名,t=never、always和auto。

n         --dereference(或-L)——显示有符号链接引用的项目

n         --directory(或者-d)——显示目录的信息而不是目录的内容

n         --dired(或者-D)——使用emacs dired模式输出

n         --escape(或者-b)——显示八进制的退出码。

n         --file-type(或者-p)——和--classify一样

n         --format=across(或者-x)——根据行来排序

n         --format=commas(或者-m)——使用逗号来吧文件名分开

n         --format=long(或者-l)——显示文件的明细的列表

n         --format=single-column(或者-l)——每行显示一个文件

n         --format=verbose——和long格式相同

n         --format=vertical(或者-C)——所有文件一列

n         --full-time——显示时间和日期的全格式。

n         --hide-control-chars(或者-q)——不可显示的文件名以问号来显示

n         --human-readable(或者-h)——以千字节为单位来显示文件的大小

n         --ignore=p(或者-I)——忽略匹配模式p的文件

n         --ignore-backups(或者-B)——不显示以~结尾的文件

n         --indicator-style=classify——和--classify一样

n         --indicator-style=none——不对文件进行分类

n         --indicator-style=file-type——和—file-type开关一样

n         --inode(或者-i)——显示文件的节点号

n         --kilobytes(或者-k)——以1024字节为单位显示文件的大小

n         -f——不排序,开启-aU,关闭-lst

n         --literal(或者-N)——显示不可打印字符,和-q开关类似

n         --no-group(或者-G)——隐藏文件的组名

n         --numeric-uid-gid(或者-n)——显示UID和GID号码,而不是名字。

n         -o——显示长列表,而不显示组属性

n         --quote-name(或者-Q)——以双引号将文件名封闭起来

n         --quoting-style=literal——和—literal一样

n         --quoting-style=local——使用本地引用风格封闭单独的文件名

n         --quoting-style=shell——使用外壳引用封闭单独的文件名

n         --quoting-style=shell-always——总是使用外壳引用封闭单独的文件名

n         --quoting-style=c——使用C语言的字符串格式封闭文件名

n         --quoting-style=escape——使用斜杠表示退出字符

n         --recursive(或者-r)——和排序的顺序相反

n         --recursive(或者-R)——显示子目录中的内容

n         --si(或者-h)——和—human-readable类型,但是以1000为单位而不是1024

n         --size(或者-s)——显示文件的大小

n         --sort=size(或者-S)——根据文件的尺寸进行排序

n         --sort=extension(或者-X)——根据文件的后缀进行排序

n         --sor=none(或者-U)——根据文件保存在目录的顺序进行排序

n         --sort=time(或者-t)——根据时间进行排序。缺省时,--time=ctime

n         --sort=version(或者-v)——考虑到GNU的版本号,根据字符顺序进行排序。

n         --time=atime(或者-u)——根据访问时间排序

n         --time=access——和上面一条相同

n         --time=use——和ctime相同

n         --time=ctime(或者-c)——显示变更时间:如果有-t,根据更改时间进行排序

n         --time=status——和ctime相同

n         --tabsize=n(或者-T)——假定Tab停止在每n个字符,而不是8个字符。

n         --width=n(或者-w)——假定屏幕是n个字符宽度而不是屏幕的实际值

printf格式码


n         %b——扩展斜杠序列

n         %c——显示一个字符

n         %d——显示有符号数

n         %e——显示浮点数,使用科学计数法

n         %f——显示浮点数

n         %g——根据变量的值,选择%f和%e

n         %i——和%d相同

n         %o——显示八进制数

n         %q——应用一个字符串,以便它可以被外壳脚本正确的读写

n         %s——显示未引用字符串

n         %u——显示无符号数

n         %x——显示无符号16进制数据,使用小写字符

n         %X——显示无符号16进制数,使用大写字符

n         %%——显示百分号“%”

printf的斜杠引导的代码


n         /b——后退一个

n         /f——换页

n         /n——换行

n         /r——回车

n         /t——Tab

n         /v——垂直Tab

n         /’——单引号字符(为了兼容C语言)

n         //——斜杠

n         /0n——n是一个八进制数表示一个8位的ASCII字符

rm命令开关


n         --directory(或者-d)——删除目录

n         --force(或者-f)——不提示用户并忽略缺少的文件

n         --interactive(或者-i)——总是提示用户

n         --recursive(或者-r或-R)——删除子目录中的内容

cp命令开关


n         --archive(或者-a)——和-dpR相同

n         --backup(或者-b)——在更改文件之前备份要修改的文件,备份文件名使用~开头

n         --backup=none/off——不使用编号备份

n         --backup=numbered/t——使用编号备份

n         --backup=existing/nul——如果文件已经存在使用编号备份,否则使用波浪号

n         --backup-simple/never——总是使用波浪号备份

n         --no-dereference(或者-d)——保存链接

n         --force(或者-f)——不提示用户,总是覆盖文件

n         --interactive(或者-i)——总是提示用户

n         --link(或者-l)——建立硬链接而不是拷贝文件

n         --preserve(或者-p)——必要的话保留文件的属性和拥有者

n         --recursive(或者-R)——拷贝所有的子目录

n         -r——和上面一条类似,但是不包含管道文件的特殊处理和不能正确拷贝的文件

n         --sparse=w——裁剪稀疏文件(w=never),完全建立稀疏文件(w=always),根据命令做出裁剪(w=auto)

n         --strip-trailing-slashes——从要拷贝的文件名的路径中删除尾部的斜杠

n         --symbolic-link(或-s)——建立一个符号链接而不是拷贝文件

n         --suffix=s(或者-S s)——使用新的后缀字符串s替换路径后缀

n         --target-directory=d——拷贝文件到目录d中

n         --update(或者-u)——覆盖旧的文件或拷贝缺少的文件

n         --one-file-system(或者-x)——留在当前的文件系统中

mv命令开关


n         --backup(或者-b)——删除文件前,使用~加文件名的文件备份要删除的文件

n         --backup=none/off——不使用编号备份

n         --backup=numbered/t——总是使用编号备份

n         --backup=existing/nul——如果文件存在使用编号备份,否则使用波浪号备份

n         --backup=simple/never——总是使用波浪号备份

n         --force(或者-f)——从不提示用户,总是覆盖

n         --interactive(或者-i)——总是提示用户

n         --strip-trailing-slashes——将要拷贝的文件的路径名尾部的斜杠删除

n         --suffix=s(或者-S)——使用新的后缀字符串替换路径后缀

n         --target-directory=d——拷贝文件到目录d中

n         --update(或者-u)——覆盖旧的文件或拷贝缺少的文件