23

首先我们先回顾下bash现有的重定向符号

1.重定向输入输出,目标是文件word

[n]<word    默认n为0
[n]>word    默认n为1
[n]>|word   默认n为1    noclobber选项有关,直接例子就明白它的用处了
[n]>>word   默认n为1
igi@igi-debian:~$ rm -f testfile
igi@igi-debian:~$ touch testfile
igi@igi-debian:~$ cat testfile
igi@igi-debian:~$ set -o noclobber
igi@igi-debian:~$ echo 2 >testfile
bash: testfile: cannot overwrite existing file
igi@igi-debian:~$ echo 2 >| testfile
igi@igi-debian:~$ cat testfile
2

2.重定向标准错误和标准输出到指定文件描述符

&>word      更通用
>&word
>word 2>&1

追加输出

&>>word     没有>>&word的表达方法
>>word 2>&1

3.Here Documents

 <<[-]word
   here-document
delimiter
-符号将删除所有行开头的tab符

4.Here Strings

<<<word

5.复制文件描述符

[n]<&word   默认n为0,如果为数字,必须得为打开的文件描述符
[n]<&-      关闭文件描述符

[n]>&word   默认n为1,如果为数字,必须得为打开的文件描述符
[n]>&-      关闭文件描述符

6.移动文件描述符

[n]<&digit- 默认n为0
[n]>&digit- 默认n为1

7.以读写方式打开文件描述符

[n]<>word   文件不在时会被创建

如果要深刻理解重定向,先要明白以下2点
1.shell(bash或者csh等)负责重定向,对于程序或者函数,这一切都是透明的,它只管输入输出,至于从哪输入哪输出,是shell解释器负责
2.shell命令解析过程中,在实际执行命令前,IO重定向先设置好

我们来看以下的例子

1.’echo 1 a1 >a2′ 与 ‘echo 1 >a2 a1′

igi@igi-debian:~$ echo 1 a1 >a2
igi@igi-debian:~$ cat a2
1 a1
igi@igi-debian:~$ rm a2
igi@igi-debian:~$ echo 1 >a2 a1
igi@igi-debian:~$ cat a2
1 a1

IO重定向是在命令执行前设置好,所以上面两种情况,最后的效果一样,bash先把输出重定向到a2文件,再执行’echo 1 a1′

2.’ls nothisfile >res 2>&1′ 与 ‘ls nothisfile 2>&1 >res’

igi@igi-debian:~/rtest$ ls nothisfile
ls: cannot access nothisfile: No such file or directory
igi@igi-debian:~/rtest$ ls nothisfile >res 2>&1
igi@igi-debian:~/rtest$ cat res
ls: cannot access nothisfile: No such file or directory
igi@igi-debian:~/rtest$ ls nothisfile 2>&1 >res
ls: cannot access nothisfile: No such file or directory
igi@igi-debian:~/rtest$ cat res
igi@igi-debian:~/rtest$ ls -1
a
b
c
res
igi@igi-debian:~/rtest$ ls -1 2>&1 >res
igi@igi-debian:~/rtest$ cat res
a
b
c
res

‘ls nothisfile >res 2>&1′,文件描述符1被重定向到文件res(本来是标准输出),然后再把文件描述符2重定向到文件描述符1(此时是文件描述符1指向文件res),最后执行”ls nothisfile”,产生错误,被送往文件描述符2,最后流向文件res。
‘ls nothisfile 2>&1 >res’,文件描述符2被重定向到文件描述符1(即标准输出:屏幕),然后再把文件描述符1重定向到文件res,结果是文件描述符2被重定向到标准输出,文件描述符1被重定向到文件res,最后执行”ls nothisfile”产生的错误就被送往屏幕。

3.’ls nothisfile a >&word’ 与 ‘ls nothisfile a >&123456′

igi@igi-debian:~/test/shell$ ls -1
a
igi@igi-debian:~/test/shell$ cat a
this is a
igi@igi-debian:~/test/shell$ ls nothisfile a >&word
igi@igi-debian:~/test/shell$ cat word
ls: cannot access nothisfile: No such file or directory
a
igi@igi-debian:~/test/shell$ ls nothisfile a >&123456
-bash: 123456: Bad file descriptor
igi@igi-debian:~/test/shell$ cat 123456
cat: 123456: No such file or directory

>&这个重定向符号,在前面有提到,“重定向标准错误和标准输出到指定文件描述符“ 和 “复制文件描述符“ 都有这个符号, 实际上“重定向标准错误和标准输出到指定文件描述符“ 是 “复制文件描述符“ 的一种特别情况, 即当 [n]>&word 的n省略 且 word不是数字时, 会重定向标准错误和标准输出 到指定文件。
“ls nothisfile a >&word” , 由于word不是纯数字, bash解析成 ”重定向标准错误和标准输出到指定文件描述符“, 效果相当于 ” ls nothisfile a >word 2>&1″
“ls nothisfile a >&123456″, 由于123456是纯数字, bash解析成 “复制文件描述符”, 相当于 ” ls nothisfile a 1>&123456″ , 但由于 “ 复制文件描述符 “规定 “如果为数字,必须得为打开的文件描述符”
所以发生了错误。

4.’ls a 1>&-’ 与 ‘ ls a >&1- ‘

igi@igi-debian:~/test/shell$ ls
a
igi@igi-debian:~/test/shell$ cat a
this is a
igi@igi-debian:~/test/shell$ ls a >&1-
a
igi@igi-debian:~/test/shell$ ls a 1>&-
ls: write error: Bad file descriptor

“ ls a >&1- “, >&1-属于“移动文件描述符” 提到的 “[n]>&digit-”, 用文件描述符digit替换掉文件描述符n, n描述符被关闭.n默认为1. “ls a >&1-”, 相当与 ” ls a 1>&1- “, 把文件描述符1替换掉原
文件描述符1, 然后关闭原文件描述符1, 没发生变化, 输出依然被送到屏幕
” ls a 1>&- “, >&- 属于 “复制文件描述符” 提到的”关闭文件描述符”, ” ls a 1>&- “, 关闭了文件描述符1, 在运行” ls a”, 由于输出默认都送到文件描述符1, 而它被关闭, 报”错误的文件描述符”

5.’ls a nothisfile 1>&2-’ 与 ‘ ls a nothisfile 1<&2- '

igi@igi-debian:~/test/shell$ ls -1
a
igi@igi-debian:~/test/shell$ ls a nothisfile 1<&2-
a
igi@igi-debian:~/test/shell$ ls a nothisfile 1>&2-
a
igi@igi-debian:~/test/shell$ exec 3<>test
igi@igi-debian:~/test/shell$ ls a nothisfile 1>&3-
ls: cannot access nothisfile: No such file or directory
igi@igi-debian:~/test/shell$ cat test
a
igi@igi-debian:~/test/shell$

‘ 1>&2- ‘ 与 ‘ 1<&2- ' 是一个效果的, [n]>&digit- 和 [n]<&digit- 这两个移动文件描述符的操作, 都是移动digit 到 n , 区别在n没有指定时, <&digit- 等于 0<&digit-, 而 >&digit- 等于 1>&digit-
移动文件描述符, 就是把描诉符digit的指向给描述符n, 然后关了digit. 例子中的exec很好的解释移动文件描述符的行为, 文件描述符3被定向到文件test, 然后1>&3-, 会使得1也定向到3所定向的文件test, 然后文件描诉符3被关闭, 效果就是标准输出被定向到test文件.

, , ,

22

apt-get remove 与 apt-get autoremove、aptitude remove的不同

apt-get remove的行为我们很好理解,就是删除某个包的同时,删除依赖于它的包
例如: A 依赖于 B, B 依赖于 C
apt-get remove 删除B的同时,将删除A(很好理解,A依赖于B,B被删了,A也就无法正常运行了)

先说明下apt-get autoremove与aptitude remove是一样的效果的, 我们先了解下这两者的瓜葛

apt-get一开始并没有记录auto-install的信息
在apt(0.6.44.2exp1)此版本时(06年),apt-get增加了类似于aptitude的auto-install记录(/var/lib/apt/extended_states).
此后,aptitude在版本0.4.5.1(07年)转向使用apt-get的auto-install记录,而抛弃了自己原先的记录方式
再随后apt-get在版本0.7.7(07年)增加了autoremove的选项

依赖关系是一个复杂而交错的链条,我们把举几个例子来看看它们的行为

以下图中, 绿色圆是为了满足依赖关系而apt-get或aptitude自动安装上的包
蓝色圆是管理员使用apt-get install 或 aptitude install
指定安装的包,简称为手动安装的包

例子1:
1. C 依赖于或推荐B软件包(apt-get和aptitude在安装软件时除了安装必要的依赖包,默认也会安装Recommends关系的包)
2. B 依赖于或推荐A, A被其他手动安装的包依赖

apt-get remove C         将删除C, 同时提示你用apt-get autoremove去清除B
apt-get autoremove C     将删除B, C
aptitude remove C        将删除B, C

我的理解: 删除C, 那么B这个包既是自动安装的,且没有其他手动安装的包依赖于它,
则可以判定B也是没必要的

例子2:
1. 在例子1的基础上, D 依赖于或者推荐B, 且D没有被其他手动安装的包依赖
这样的情况一般出现在用apt-get remove 某个手动安装的包之后.

apt-get remove C 将删除C, 同时提示你用apt-get autoremove去清除B,D apt-get autoremove C 将删除B, C, D aptitude remove C 将删除B, C, D

我的理解: 删除C, 那么B,D 这两个包既是自动安装的,且没有其他手动安装的包依赖于它们,
则可以判定B,D也是没必要的

例子3:
1. 在例子2的基础上, 有个手动安装的包E推荐D(既E Recommends D,手动安装E时,也会把D装上)

apt-get remove C         将删除C, 同时提示你用apt-get autoremove去清除B,D
apt-get autoremove C     将删除B, C, D
aptitude remove C        将删除B, C, D

我的理解: 删除C, 那么B,D 这两个包既是自动安装的,且没有其他手动安装的包依赖于它们,
则可以判定B,D也是没必要的
虽然D被E Recommend, 但为啥是这么设计的, 我也没猜出开发人员的想法

例子4:
1. 在例子3的基础上, D变成依赖于B, E变成依赖于D

apt-get remove C         将删除C
apt-get autoremove C     将删除C
aptitude remove C        将删除C

我的理解: 只删除C, 因为B被D依赖, D被E依赖, 间接来说,E不能没有B,D而正常运行,所以B,D被保留

例子5:
1. 在例子4的基础上, D变成推荐B, E依然依赖于D

apt-get remove C         将删除C, 同时提示你用apt-get autoremove去清除B
apt-get autoremove C     将删除B, C
aptitude remove C        将删除B, C

我的理解: 删除C, 而B没有被其他手动安装的包直接依赖或者间接依赖(我指那些一层层depend on的关系), D被E依赖
所以B不是必要的,可以删除, 而D不能删除

, , ,

25

帮一师弟解决一个无法通过公钥登录ssh服务器问题, 顺便总结下

现象: test帐号使用key无法登录某ssh服务器, 而同机器下的test2帐号却可以登录, 两个帐号都可以通过密码登录

在排查了所有配置错误的可能后, 初步怀疑test帐号的权限设置出问题

test@client:~$ ls -l ~/.ssh/
-rw------- 1 test test   1675 2010-03-25 15:15 id_rsa
test@server:~$ ls -l ~/.ssh/
-rw-r--r-- 1 test test    396 2010-03-25 15:15 authorized_keys

查看了客户端及服务器端的.ssh目录下的公钥与私钥权限, 可以看出, 并没有问题
私钥必须是600权限, 而公钥至少是644或者更严格的权限, 这都符合, 但依然无法登录

test@server:~$ ls -la ~ | grep -w .ssh
drwxr-xr-x  2 test  test  4.0K 12-23 16:59 .ssh

查看了服务器端的.ssh目录权限, 是755, 也是没问题的, ssh服务器要求在使用key登录时.ssh目录的权限必须是其他用户不可写。
一开始实在想不明为啥test2帐号使用key可以登录,test帐号使用key无法登录, ssh_config和sshd_config在检查了多遍后确实没有问题, 最后在服务器端对比两个帐号的不同时, 发现了可疑的地方

$ls -l /home/
drwxrwxrwx   3 test test 4096 2009-12-31 17:31 test
drwxr-xr-x   6 test2 test2 4096 2010-03-23 15:59 test2

两个帐号的home目录权限不同, test帐号是777, test2帐号是755, 会不会是这里不同导致的? 在服务器端把test目录修改成777后, 解决问题

为啥home目录的权限也会影响ssh的key登录?

ssh服务器的key方式登录对权限要求严格。对于客户端: 私钥必须为600权限或者更严格权限(400), 一旦其他用户可读, 私钥就不起作用(如640), 表现为系统认为不存在私钥
对于服务器端: 要求必须公钥其他用户不可写, 一旦其他用户可写(如660), 就无法用key登录, 表现为:Permission denied (publickey).
同时要求.ssh目录其他用户不可写,一旦其他用户可写(如770), 就无法使用key登录, 表现为:Permission denied (publickey).

但为什么home目录的可写也影响到ssh使用key登录?

我们知道linux下目录也是文件, 目录其他用户可写,代表其他用户可以删除目录里的所有文件或子目录,重命名目录下的所有文件或子目录.
home目录的可写,表示其他用户对.ssh子目录也有改写的权限(删除或重命令),也就导致ssh判断.ssh为其他用户可写, 拒绝使用key登录

, ,