Closed lujun9972 closed 5 years ago
loginshell=yes
if [ -n "$loginshell" ]
有些为了方便用户而设置的信息,用非交互式shell来读取是相当浪费时间的.
if [ -n "$loginshell" ] then #登录shell的相关设置 fi
在许多UNIX中若存在$HOME/.hushlogin文件,则登录过程会不显示/etc/motd中的登录信息. 因此可以使用如下脚本来让只有/etc/motd中信息修改过后才显示
files=$(ls -t /etc/motd ~/.hushlogin ) newerFile=$(echo $files|cut -d " " -f1) if[ $newerFile == /etc/motd ] then cat /etc/motd touch ~/.hushlogin fi unset files unset newerFile
在C shell中有一个名为.logout的设置文件. 当用户退出时.logout中的命令被执行. 但是Bourne 和Korn shell中都没有退出文件. 可以使用一下方式模拟
在用户的.profile加入一行
trap '. ~/.sh_logout;exit' 0
可以通过设置ignoreeof这个shell变量来解决问题:
对于C shell执行
set ignoreeof
对于bash或ksh使用
set -o ignoreeof
echo "something error" 1>&2
如何让bash不执行shell函数,只执行内部/外部命令
在命令前输入command即可以禁止shell函数查找
cd () { command cd "$@" # 这里只会执行命令shell而不会执行cd函数 setvars }
如何强制bash使用内部命令呢
在命令前输入builtin
builtin echo -n "this should be the builtin command echo" # 使用内置命令echo
如何强制bash使用外置命令呢?
只需要给出外部命令的全路径即可.
/bin/echo hi # 明确指明使用哪个外部命令
或者也可以使用enable -n将某个/某几个内置bash命令无效化. enable的影响将一直持续到用户退出shell为止.
enable -n echo ls # 禁用内置命令echo和ls enable ls # 重新启动内置命令ls enable -a # 列出所有bash内置命令的状态
可以在EOF标识前放一个反斜杠
# 下面命令会显示$PATH cat <<\EOF $PATH EOF # 下面命令会显示$PATH的值 cat <<EOF $PATH EOF
通配符匹配只对已经存在的文件名作扩展.
而{}模式,则可以对任意文本进行扩展,{}的用法为{扩展1,扩展2,扩展3…}. 例如
cp filename{,.bak} # 相当于 cp filename filename.bak vi /tmp/file{a,b,c,d,e} # 相当于 vi /tmp/filea /tmp/fileb /tmp/filec /tmp/filed /tmp/filee
其中pattern采取的是通配符模式,而不是正则表达式. 例如
var=/home/tmp/work/file.a.el则 echo ${var#/*/} # tmp/work/file.a.el echo ${var##/*/} # file.a.el echo ${var%.*} # /home/tmp/work/file.a echo ${var%%.*} # /home/tmp/work/file echo ${var%/*} # /home/tmp/work可以用于取出目录值
bash中的<(process)被用来执行process并将输出送到一个命令的命名管道中.
可以把它想象成一个文件名参数,文件的内容就是process执行的结果.
若使用的shell没有这个功能,可以用一个shell脚本来代替,该脚本执行一个命令,并将其输出保持到一个临时文件中,然后将临时文件名放到它的标准输出中.
p() { eval "$@" >tmp.$$ 2>&1 echo tmp.$$ }
如何设置历史命令的数量
ksh和bash中,设置变量HISTSIZE的值即可
如何列出已保存的历史命令
使用history [N]列出所有/后N个命令
bash/csh中的历史替换
!N
ls /tmp echo !$ # 等于 echo /tmp
diff file1 file2
输出的结果为如何将file1变成file2的过程,描述使用了ed的命令说明(c为修改行,d为删除行,a为添加行)
可以使用-e选项来输出供ex/ed使用的脚本
diff3 file1 file2 file3
输出的结果为如何将file2和file3变成file1的过程,描述使用了ed的命令说明(c为修改行,d为删除行,a为添加行)
ediff file1 file2
diff的输出大量使用了ed的命令来说明,难以理解,可以使用ediff,它会将说明翻译为英文
comm [-1] [-2] [-3] file1 file2
file1和file2必须是已经排过序的
comm命令显示三列信息
要想不显示那一列的信息,使用-N选项即刻.
使用stty tostop停止后台输出
正常情况下,后台运行的作业也会把输出输出到用户的屏幕上,这样容易搞乱屏幕. 可以使用stty tostop命令来让试图对终端写入的后台作业停止运行.
若后台作业因为输出到终端而停止,则shell会打印出一条信息:\+ stopped (tty output) somejob
\+ stopped (tty output) somejob
标识作业的几种方法
%1表示第1号作业.
%vi表示匹配以vi开头的命令行的作业
%?fn表示命令行中包含fn的作业
作业控制的快捷方式
fg %2 # 等于 %2
bg %2 # 等于 %2 &
如何仅将标准错误发送給管道?
默认情况下,只有命令的表示输出才回发送到管道中,若要仅将标准错误发送給管道可以使用subshell. 如下所示
(command1 >/dev/null) 2>&1 |command2
或者使用如下方式交换stderr和stdout
command1 3>&2 2>&1 1>&3 |command2
使用noclobber确保IO重定向的安全性
在bash/ksh中设置set -o noclobber后,则shell将不允许IO重定向破坏一个已经存在的文件. 除非在重定向的符号之后添加一个!来显式的通知他.
set -o noclobber
set -o noclobber ls # filea fileb ls >filea # bash: filea: Cannot clobber existing file ls >|filea # 没问题,filea被覆盖了
使用subshell来组合几个命令的输出整合起来实现IO重定向
(cat filea1;echo .bp;cat file2) |nroff (date;who;ls) >log
使用{}列表来组合几个命令的输出,实现整体的IO重定向
{ date who ls } > log
使用{}列表与sushell的不同在与,{}的所有操作都是基于当前shell来操作的.
使用tee命令将输出发送到多个地方
若希望一个程序的输出重定向到一个文件的同时也在屏幕上输出,则可以使用tee命令.
tee命令会将它的标准输入写入到一个文件中,并将相同的文本写入到他的标准输出中.它的格式为:tee [-a] file
ls |tee ls.log # 将ls的结果保存到ls.log中,同时输出到屏幕上 ls |tee -a ls.log # tee -a的意思是将结果添加到ls.log中
&- 关闭标准输出 ksh的文件通配符说明
&- 关闭标准输出
?(abc)
匹配0个或1个abc
*(abc)
匹配0个或多个abc
+(abc)
匹配1个或多个abc
!(abc)
匹配不包含abc的任何字符串
使用tar实现目录树的拷贝
使用tar打包目录到标准输出|从标准输出tar解包
tar cf - . | (cd ~/backup && tar xBf -) # 需要注意,这里tar -cf不能加参数v,因为有些tar命令的v选项会使得详细输出输出到标准输出而不是标准错误中,从而破坏tar的流
使用tar的X标识可以指定哪些文件不包含在打包/解包的范围内
tar的X标志后接一个文件,文件的内容就是排除打包的文件路径列表
echo *~ >/tmp/ExcludeTar tar -cvf e.tar -X /tmp/ExcludeTar . # 排除所有以~结尾的文件 tar -xvf e.tar -X /tmp/ExcludeTar # 解包时排除所有以~结尾的文件
请注意tar打包时是使用的相对路径还是绝对路径
使用-C标识,可以指定tar在打包前先进入指定目录,然后就可以指定相对路径打包了
cd tar -cvf t.tar dir1 -C /tmp/dir2 . # 打包的内容包括~/dir1 /tmp/dir2的内容, tar -tvf t.tar # 但路径都为./
使用tar将多个小文件打包以节约空间的想法是行不通的.
这是因为,tar实际上是为磁带归档所设计的. 它会在每个文件的末尾加上垃圾空字符以沾满一个块的空间,因此实际上一个大的tar文件和里面单独小文件所占用的磁盘块差不多.
但是可以通过对tar包进行压缩的方式来解决这个问题,因为大量的空字符实际上非常适用于压缩算法.
find命令中的逻辑表达式可以包含括号
find . -atime +5 \( -name "*.o" -o -name "*.tmp" \) -print # 这里的要用\(\),因为()是subshell的操作符
find的-exec也能作为匹配测试条件,当它所执行的命令返回一个0退出状态时,返回真. 例如
find . -exec myTest {} \; -print # 只有通过myTest的文件才会输出
find的-exec只认识独立的{}. 若{}和其他字符结合,则不再被替换为查找到的文件. 例如
find. -type d -exec mkdir /usr/project/{} \; # 这里的{}不会被扩展 # 需要改为 find . -type d -print |sed 's@^@/usr/project/@' |xargs mkdir # 先用sed转换,再传给mkdir来创建目录
使用find删除名字特殊的文件
使用find命令查找特定的inode索引号,并使用-exec执行rm或mv操作
ls -i find . -inum 9620 -exec rm {} \; find . -inum 9620 -exec mv {} ordinaryname \;
find命令需要读取它所搜索的目录树中的每个索引节点,因此最好尽可能地把多个内容组合到单个find命令中. 方法为
find . \( -type d -a -exec chmod 771 {} \; \) -o \ \( -name "*.BAK" -a -exec chmod 600 {} \; \) -o \ \( -name "*.sh" -a -exec chmod 755 {} \; \) -o \ \( -name "*.txt" -a -exec chmod 644 {} \; \) -o \
为了提高find的效率,可以考虑创建自己的find数据库
创建find数据库
cd find . -print |sed "s@^./@@" > ~/.fastfinddb # 存储~/下的所有文件信息,并替换到./
创建cron定时运行该脚本.
创建一个shell脚本来使用这个数据库
ffind() { egrep "$1" ~/.fastfinddb |sed "s@^@$HOME/@" # 在查询结果前添加$HOME }
ln的最后一个参数可以是一个目录,表示建立与之前参数的同名连接存放在目录中.
ln f1 f2 f3 /tmp # 在/tmp下创建名为f1 f2 f3的链接
ln可以只带一个参数,表示在当前目录建立与第一个参数同名的链接
cd /tmp ln ~/bin/file # 在/tmp创建一个名为file的链接,链接到~/bin/file下
expr arg1 operator arg2 [operator arg3…]
如果表达式的值非0并且非空,那么expr的退出状态值为0;如果表达式的值为0或者空,则退出状态值为1;如果表达式无效,则退出状态值为2
算术操作符
expr \( 5 + 10 \) / 2 # 7
大于
= 大于等于
逻辑操作符
p="version.100" expr "$p" : '.*' # 11 expr "$p" : '\(.*\)' # "version.100"
scale=N 设置结果的精度为小数点后N位
echo "scale=2;10/4"|bc # 结果为2.50
obase=N 设置是输出的数字以N进制为单位
需要注意的是,若先设置ibase=N,再设置obase=M时,M已经是以N进制来计算了,例如
echo "ibase=8;obase=16;17" |bc # 结果为11
之所以结果为11是因为obase的16使用的是8进制,它的值其实是14
yes会不断重复地输出它的参数(默认为y),使用它和head命令一起可以生成任意长度大小的文件. 例如
要生成每行8个字符(7个数字和一个换行符),共12800行的文件,则输入
yes 1234567 |head -12800 >file
用户在进入/退出目录时,自动执行脚本
cd (){ test -r .exit.sh && . .exit.sh builtin cd "$1" test -r .enter.sh &&. .enter.sh }
使用grep -c 可以统计每个文件匹配模式的数量,通过这种方法可以抽取出不匹配模式的那些文件
vgrep() { case $# in 0|1) echo "Usage: `basename $0` pattern file [files...]" 1>&2 ;; *) pattern = $1 shift grep -c $pattern "$@" |sed -n 's/:0$//p' ;; esac }
如何区分change time和modification time
change time是对文件的inode进行修改,比如文件名,权限等
modification time是对文件的内容进行修改
一般情况下,使用mv移动一个文件时,并不改变所有权.
但若是跨文件系统移动文件,那么被移动的文件的所有者将改为你.
这时因为,在跨文件系统移动时,mv实际上必须拷贝该文件,并删除原文件
使用目录的sticky位保护文件
一般情况下,若一个用户又对某目录的写权限,则它可以对该目录中的文件进行重命名或者删除操作–即使文件并不属于该用户.
通过设置目录的sticky位(1000)可以使得只有文件的所有者,目录的所有者和超级用户才能对文件进行重命名或删除.
chmod 1777 ~/tmp chmod +t ~/tmp ls -l ~/tmp # /tmp的属性显示为drwxrwxrwt,最后的t标识sticky位
如何清空其他终端上的屏幕
终端的标准输出被映射成了/dev/中的tty文件了,而clear清除屏幕的方法是通过TERMINFO查询终端的清除键序列,然后输出该键序列到标准输出中.
因此,若终端类型一致,且用户具有对/dev/tty文件的写权限的化,可以通过clear>/dev/tty来实现清空其他终端上内容
who |grep darksun # darksun pts/6 9月24 20时2 (10.8.201.68) clear >/dev/pts/6 # 清空/dev/pts/6的屏幕显示
使用/dev/null链接为无用的日志文件可以节省空间
假设某个进程会不断的写日志到~/logfile中,而该日志并无用处,则可以
ln /dev/null ~/logfile
如何为file增加文件类型的识别
通过修改/etc/magic能够增加可识别的文件类型
/etc/magic有四个字段:
offset data-type value file-type
文件中的偏移量,从0开始计算. 表示file从该偏移量开始匹配
测试类型. 文本比较用string,字节比较用offset,两字节比较用short,四字节比较用long
用户希望的值,若datea-type为串比较,则可以是任何字符串,可以包括UNIX转义序列. 若为字节比较则必须是一个数字
若测试成功,file会打印的值
crush:一个略过所有空白行的cat
使用sed将所有空白行删掉
#!/bin/sed -f /^[ ]*$/d
如何在每行输出后增加1/N行的空白间距?
使用sed的G命令可以实现功能. sed的G命令附加了一个换行符和sed所保留空格的内容.
增加一行空白间距的方法为
exec /bin/sed G $@
同理,增加2行空白间距的方法为
exec /bin/sed 'G;G' $@
可以通过临时设置环境变量TZ的值,然后执行date的方式,来获得其他地区的时间. 例如
(TZ=Japanf9;date) # 获取日本现在的时刻
export后的shell变量就是环境变量. subshell会从shell中继承所有的环境变量,但不会继承shell变量
执行cd foo时,shell会先尝试进入当前目录的foo目录下,若失败,则会遍历CDPATH中的各目录,并一一尝试进入其中的foo目录下
CDPATH=:~ # 注意最开始的:,它是一个空记录项,表示当前目录,若没有这个当前目录的记录,则无论是sh还是ksh都无法cd到当前目录的子目录中!!bash不存在这个问题 cd ~/bin cd bin # 若不存在~/bin/bin目录,则进入~/bin目录下
使用
启动vi或ex编辑器时,会自动执行保存在~/.exrc内的初始化命令.
初始化命令可以是set,ab和map. 注释由双引号"开头.
由于该文件实际上是进入vi前由ex读取的,因此exrc中的命令不应该有前置的冒号
除了.exrc文件外,还可以在其他文件中保持设置的选项,并在vi中用:so命令来读取.
因此:e#的意思是切换到另一个替换文件,功能等同于C-^
:w %.bak的意思是
:.,600w newfile 把当前行到第600行的内容写入newfile中
:.,600w >>newfile 可以把当前行到600行的内容添加到newfile中,而不覆盖原newfile的内容
象/Los Alamos/;/treasure/表示找到出现在Los Alamos后的treasure处,即使这两个短语可能不在同一行.
类似于/Los Alamos然后再/treasure. 不同的是,它可以使用n命令来重复搜索
可以通过设置tags的属性来设置多个tags文件.
:ab 缩写 全称
还可以用:unab 缩写来取消缩写词定义.
:ab 则会列出当前已定义的缩写词
需要特别说明的是: ab定义的缩写词,对ex模式也生效,事实上,对ex模式下的命令,用缩写词比用键映射更好.
:set directory=/some/place/new
使用map智能在命令模式下定义宏.
使用map!的作用类似map,但是map!在文本输入模式下起作用,它的功能类似ab
vi虽然不支持使用q来定义宏,但是支持用@来执行宏.
使用程序qterm查询用户终端类型
在.profile中放入下面一句:
TERM=`qterm`;export TERM
set -xv
通过输入stty erase {控制字符} 可以将{控制字符}设定为删除键.
stty让用户用两个字符的组合char来代表一个控制键. 其中^就是键^本身,而{char}是任意的单个字符. 可能需要在{char}前放入一个\,以防止shell将其解释为一个通配符
例如
stty erase ^h stty erase ^\?
stty可以改变的功能包括:
用stty -a会显示用户当前所有终端的设置. werase和rprnt字符有些UNIX版本未实现.
可以通过搜索/etc/termcap文件内容或者通过列出在/usr/lib/terminfo目录结构中的文件名来寻找终端名,以方便地设置TERM
使用split分割
split -N bigfile # 每N行分割一个文件,分割产生的文件以xaa,xab这样命名 split -N bigfile bigfile.split. # 每N行分割一个文件,分割产生的文件以bigfile.split.aa,bigfile.split.ab这样命名
使用sed来实现
split_line=$1 file=$2 total_line=$(wc -l $file |cut -d " " -f1) prefix=$file.split. i=1 begin_line=1 while [ $begin_line -le $total_line ] do end_line=$(echo "$begin_line+$split_line" |bc) sed "$begin_line,$end_line!d" $file >$prefix$i i=$(echo "$i+1" |bc) begin_line=$(echo "$end_line+1"|bc) done
split -b N bigfile # 以N个字节来分割 split -b N bigfile prefix. # 以N个字节来分割,且分割的文件前缀为prefix.
使用dd分割
split_byte=$1 file=$2 total_byte=$(wc -c <$file) prefix=$file.split. i=1 begin_byte=1 while [ $begin_byte -le $total_byte ] do dd of=$prefix$i bs=$split_byte count=1 2>/dev/null i=$(echo "$i+1" |bc) begin_byte=$(echo "$begin_byte+$split_byte" |bc) done <$file
若希望并排粘贴N个文件的内容,则可以使用paste命令
paste <(ls) <(ls -r) # my-byte-split.sh my-line-split.sh # my-line-split.sh my-byte-split.sh
合并的数据流默认情况下使用TAB分割,但是可以用-d选项来指定分隔符。
join会在文件中搜索某些列,找到相互匹配的行之后,它会在该列的位置上把两列文本粘帖在一起
默认join会以第一列的内容进行匹配,也可以使用-1 FIELD和-2 FIELD来指定file1和file2的FIELD列
需要注意的是:
uniq file1 file2
的意思是用file1的唯一行代替file2的内容
选项
sort +2 -3 +0 -2 phonelist # 先根据第2列的值排序,再根据第0列和第1列的值进行排序
sort +2 -3 +0 -2 +3n phonelist # 先根据第2列的值排序,再根据第0列和第1列的值进行排序,最后根据第三列进行数字排序
sort排序规则
{TAB}12 345 678中参与第0列排序的是{TAB}12而不是12
根据长度对行进行排序
#! /bin/sh awk 'BEGIN { FS=RS } {print length,$0}' $* | sort +0n -1 | # 根据数字大小进行排序 sed 's/^[0-9][0-9]*//' # 删除数字大小
case i in ?) # 匹配只有1个字符的字符串 ;; ?*) # 匹配有一个或多个字符的字符串 ;; [yY]|[yY][eE][sS]) # 匹配y,Y或者YES,Yes,YeS等 ;; /*/*[0-9]) # 匹配以/开始并且至少再包含一个/的一数字结尾的文件路径名,例如/xxx/yyy/somedir/file2 ;; 'what now?') # 匹配模式what now?。引号告诉shell按字面意思解释 ;; "$msgs") # 匹配$msgs变量的内容。双引号允许shell替换变量的值 ;; *) # 匹配所有的值,起默认值的作用
trap "command1;command2…" sign1 sign2…
捕获到sign1,sign2…等信号后,执行command1;command2
使用set 新参数1 新参数2…能够初始化脚本的参数。
#set_test.sh echo before set : $@ set 1 2 echo after set : $@ # set_test.sh 3 4 # before set : 3 4 # after set : 1 2
但要注意的是,若新参数以-开头的,则shell会把它看出是自己的选项。
jot 要产生多少个参数 [起始参数值 结束参数值]
exec command会执行comand来代替当前shell,它常常用于shell脚本的最后一个命令.
但exec也可以用来重定向当前shell脚本的IO,例如
exec < formfile
上面命令使得当前shell中所有命令的标准输入来自于文件formfile
:操作符会计算它的参数值,并返回0退出状态,它可以用来
#! /bin/bash #假设该脚本名称为test.sh commands...
则在直接执行该脚本时,内核实际上执行的是
/bin/bash test.sh
这也是为什么用awk作为#!行的命令解释程序时,需要加-f的原因,因为-f表示用从文件中读取脚本.
#! /usr/bin/awk -f {print $2}
因此使用#!/bin/cp可以制作自复制脚本. 将它放到名为zap的文件中,运行zap zup,则会有一份zup的自拷贝
另外,需要注意,内核不会去搜索PATH路径,因此#!中的解释程序必须使用绝对路径.
使用trap : sign1 sign2…
会忽略信号,向子进程传递信号
使用stty -echo就能关闭回显,这样用户的输入就不会显示在屏幕上了
echo "enter the password" stty -echo read pwd stty echo
sh<file若file中有无法进行read操作
掩码只会在文件存在时起作用.如果文件尚不存在,掩码就不会应用于它. 基于该特性,可以创建一个锁文件
name = $(basename $0) LOCKFILE=/tmp.lock.$name until (umask 222;echo $$ >$LOCKFILE) 2>/dev/null # 若已 存在锁文件,则该操作失败,否则成功 do sleep 5 done rm -f $LOCKFILE
事实上,可以通过如下命令来创建模式为000的文件
(umask 666;echo hi >afile)
你为何如此优秀?
shell
shell分类
loginshell=yes
,然后就可以通过if [ -n "$loginshell" ]
来判断shell的类型有些为了方便用户而设置的信息,用非交互式shell来读取是相当浪费时间的.
如何判断用户从不同终端登录
在许多UNIX中若存在$HOME/.hushlogin文件,则登录过程会不显示/etc/motd中的登录信息. 因此可以使用如下脚本来让只有/etc/motd中信息修改过后才显示
如何在sh退出时自动执行命令
在C shell中有一个名为.logout的设置文件. 当用户退出时.logout中的命令被执行. 但是Bourne 和Korn shell中都没有退出文件. 可以使用一下方式模拟
在用户的.profile加入一行
如何防止shell意外退出
可以通过设置ignoreeof这个shell变量来解决问题:
对于C shell执行
对于bash或ksh使用
shell解释命令行的步骤是怎样的
如何使用echo信息到标准错误中
如何强制bash执行外置/内置命令?
如何让bash不执行shell函数,只执行内部/外部命令
在命令前输入command即可以禁止shell函数查找
如何强制bash使用内部命令呢
在命令前输入builtin
如何强制bash使用外置命令呢?
只需要给出外部命令的全路径即可.
或者也可以使用enable -n将某个/某几个内置bash命令无效化. enable的影响将一直持续到用户退出shell为止.
如何禁止here Document中的变量替换和命令替换呢?
可以在EOF标识前放一个反斜杠
shell中通配符与{}模式的区别
通配符匹配只对已经存在的文件名作扩展.
而{}模式,则可以对任意文本进行扩展,{}的用法为{扩展1,扩展2,扩展3…}. 例如
ksh和bash中的变量编辑
其中pattern采取的是通配符模式,而不是正则表达式. 例如
bash中的进程替换
bash中的<(process)被用来执行process并将输出送到一个命令的命名管道中.
可以把它想象成一个文件名参数,文件的内容就是process执行的结果.
若使用的shell没有这个功能,可以用一个shell脚本来代替,该脚本执行一个命令,并将其输出保持到一个临时文件中,然后将临时文件名放到它的标准输出中.
shell中的历史替换机制
如何设置历史命令的数量
ksh和bash中,设置变量HISTSIZE的值即可
如何列出已保存的历史命令
使用history [N]列出所有/后N个命令
bash/csh中的历史替换
!N
来执行编号为N的命令比较文件差异
diff file1 file2
输出的结果为如何将file1变成file2的过程,描述使用了ed的命令说明(c为修改行,d为删除行,a为添加行)
可以使用-e选项来输出供ex/ed使用的脚本
diff3 file1 file2 file3
输出的结果为如何将file2和file3变成file1的过程,描述使用了ed的命令说明(c为修改行,d为删除行,a为添加行)
可以使用-e选项来输出供ex/ed使用的脚本
ediff file1 file2
diff的输出大量使用了ed的命令来说明,难以理解,可以使用ediff,它会将说明翻译为英文
comm [-1] [-2] [-3] file1 file2
file1和file2必须是已经排过序的
comm命令显示三列信息
要想不显示那一列的信息,使用-N选项即刻.
shell的作业控制
使用stty tostop停止后台输出
正常情况下,后台运行的作业也会把输出输出到用户的屏幕上,这样容易搞乱屏幕. 可以使用stty tostop命令来让试图对终端写入的后台作业停止运行.
若后台作业因为输出到终端而停止,则shell会打印出一条信息:
\+ stopped (tty output) somejob
标识作业的几种方法
%1表示第1号作业.
%vi表示匹配以vi开头的命令行的作业
%?fn表示命令行中包含fn的作业
作业控制的快捷方式
shell的IO重定向
如何仅将标准错误发送給管道?
默认情况下,只有命令的表示输出才回发送到管道中,若要仅将标准错误发送給管道可以使用subshell. 如下所示
或者使用如下方式交换stderr和stdout
使用noclobber确保IO重定向的安全性
在bash/ksh中设置
set -o noclobber
后,则shell将不允许IO重定向破坏一个已经存在的文件. 除非在重定向的符号之后添加一个!来显式的通知他.使用subshell来组合几个命令的输出整合起来实现IO重定向
使用{}列表来组合几个命令的输出,实现整体的IO重定向
使用{}列表与sushell的不同在与,{}的所有操作都是基于当前shell来操作的.
使用tee命令将输出发送到多个地方
若希望一个程序的输出重定向到一个文件的同时也在屏幕上输出,则可以使用tee命令.
tee命令会将它的标准输入写入到一个文件中,并将相同的文本写入到他的标准输出中.它的格式为:tee [-a] file
?(abc)
匹配0个或1个abc
*(abc)
匹配0个或多个abc
+(abc)
匹配1个或多个abc
!(abc)
匹配不包含abc的任何字符串
tar命令
使用tar实现目录树的拷贝
使用tar打包目录到标准输出|从标准输出tar解包
使用tar的X标识可以指定哪些文件不包含在打包/解包的范围内
tar的X标志后接一个文件,文件的内容就是排除打包的文件路径列表
请注意tar打包时是使用的相对路径还是绝对路径
使用-C标识,可以指定tar在打包前先进入指定目录,然后就可以指定相对路径打包了
使用tar将多个小文件打包以节约空间的想法是行不通的.
这是因为,tar实际上是为磁带归档所设计的. 它会在每个文件的末尾加上垃圾空字符以沾满一个块的空间,因此实际上一个大的tar文件和里面单独小文件所占用的磁盘块差不多.
但是可以通过对tar包进行压缩的方式来解决这个问题,因为大量的空字符实际上非常适用于压缩算法.
find命令
find命令中的逻辑表达式可以包含括号
find的-exec也能作为匹配测试条件,当它所执行的命令返回一个0退出状态时,返回真. 例如
find的-exec只认识独立的{}. 若{}和其他字符结合,则不再被替换为查找到的文件. 例如
使用find删除名字特殊的文件
使用find命令查找特定的inode索引号,并使用-exec执行rm或mv操作
提高find的性能
find命令需要读取它所搜索的目录树中的每个索引节点,因此最好尽可能地把多个内容组合到单个find命令中. 方法为
为了提高find的效率,可以考虑创建自己的find数据库
创建find数据库
创建cron定时运行该脚本.
创建一个shell脚本来使用这个数据库
ln命令
ln的最后一个参数可以是一个目录,表示建立与之前参数的同名连接存放在目录中.
ln可以只带一个参数,表示在当前目录建立与第一个参数同名的链接
cat命令
tail命令
su命令
expr命令
语法
expr arg1 operator arg2 [operator arg3…]
返回值
如果表达式的值非0并且非空,那么expr的退出状态值为0;如果表达式的值为0或者空,则退出状态值为1;如果表达式无效,则退出状态值为2
operator操作符
算术操作符
逻辑操作符
bc命令进行数学运算
scale=N 设置结果的精度为小数点后N位
obase=N 设置是输出的数字以N进制为单位
需要注意的是,若先设置ibase=N,再设置obase=M时,M已经是以N进制来计算了,例如
之所以结果为11是因为obase的16使用的是8进制,它的值其实是14
yes命令生成任意大小的文件
yes会不断重复地输出它的参数(默认为y),使用它和head命令一起可以生成任意长度大小的文件. 例如
要生成每行8个字符(7个数字和一个换行符),共12800行的文件,则输入
其他
用户在进入/退出目录时,自动执行脚本
使用grep -c 可以统计每个文件匹配模式的数量,通过这种方法可以抽取出不匹配模式的那些文件
如何区分change time和modification time
change time是对文件的inode进行修改,比如文件名,权限等
modification time是对文件的内容进行修改
一般情况下,使用mv移动一个文件时,并不改变所有权.
但若是跨文件系统移动文件,那么被移动的文件的所有者将改为你.
这时因为,在跨文件系统移动时,mv实际上必须拷贝该文件,并删除原文件
使用目录的sticky位保护文件
一般情况下,若一个用户又对某目录的写权限,则它可以对该目录中的文件进行重命名或者删除操作–即使文件并不属于该用户.
通过设置目录的sticky位(1000)可以使得只有文件的所有者,目录的所有者和超级用户才能对文件进行重命名或删除.
如何清空其他终端上的屏幕
终端的标准输出被映射成了/dev/中的tty文件了,而clear清除屏幕的方法是通过TERMINFO查询终端的清除键序列,然后输出该键序列到标准输出中.
因此,若终端类型一致,且用户具有对/dev/tty文件的写权限的化,可以通过clear>/dev/tty来实现清空其他终端上内容
使用/dev/null链接为无用的日志文件可以节省空间
假设某个进程会不断的写日志到~/logfile中,而该日志并无用处,则可以
如何为file增加文件类型的识别
通过修改/etc/magic能够增加可识别的文件类型
/etc/magic有四个字段:
offset data-type value file-type
文件中的偏移量,从0开始计算. 表示file从该偏移量开始匹配
测试类型. 文本比较用string,字节比较用offset,两字节比较用short,四字节比较用long
用户希望的值,若datea-type为串比较,则可以是任何字符串,可以包括UNIX转义序列. 若为字节比较则必须是一个数字
若测试成功,file会打印的值
crush:一个略过所有空白行的cat
使用sed将所有空白行删掉
如何在每行输出后增加1/N行的空白间距?
使用sed的G命令可以实现功能. sed的G命令附加了一个换行符和sed所保留空格的内容.
增加一行空白间距的方法为
同理,增加2行空白间距的方法为
环境变量
常用的环境变量
如何显示其他地区现在的时间?
可以通过临时设置环境变量TZ的值,然后执行date的方式,来获得其他地区的时间. 例如
环境变量和shell变量的区别
export后的shell变量就是环境变量. subshell会从shell中继承所有的环境变量,但不会继承shell变量
使用CDPATH变量为用户改变目录节省时间
执行cd foo时,shell会先尝试进入当前目录的foo目录下,若失败,则会遍历CDPATH中的各目录,并一一尝试进入其中的foo目录下
获取路径中目录信息的几种方法
使用
组织$HOME目录
- ~/private存放私人文件,将权限设为700
vi
启动vi或ex编辑器时,会自动执行保存在~/.exrc内的初始化命令.
初始化命令可以是set,ab和map. 注释由双引号"开头.
由于该文件实际上是进入vi前由ex读取的,因此exrc中的命令不应该有前置的冒号
除了.exrc文件外,还可以在其他文件中保持设置的选项,并在vi中用:so命令来读取.
因此:e#的意思是切换到另一个替换文件,功能等同于C-^
:w %.bak的意思是
:.,600w newfile 把当前行到第600行的内容写入newfile中
:.,600w >>newfile 可以把当前行到600行的内容添加到newfile中,而不覆盖原newfile的内容
象/Los Alamos/;/treasure/表示找到出现在Los Alamos后的treasure处,即使这两个短语可能不在同一行.
类似于/Los Alamos然后再/treasure. 不同的是,它可以使用n命令来重复搜索
可以通过设置tags的属性来设置多个tags文件.
:ab 缩写 全称
还可以用:unab 缩写来取消缩写词定义.
:ab 则会列出当前已定义的缩写词
需要特别说明的是: ab定义的缩写词,对ex模式也生效,事实上,对ex模式下的命令,用缩写词比用键映射更好.
:set directory=/some/place/new
vi的命令模式映射:
使用map智能在命令模式下定义宏.
使用map!的作用类似map,但是map!在文本输入模式下起作用,它的功能类似ab
vi的宏定义
vi虽然不支持使用q来定义宏,但是支持用@来执行宏.
设置终端
登录时设置终端类型
使用程序qterm查询用户终端类型
在.profile中放入下面一句:
登录时,若挂起怎么办?
set -xv
,让shell进入调试模式使用stty设置删除,终止和终端字符
通过输入stty erase {控制字符} 可以将{控制字符}设定为删除键.
stty让用户用两个字符的组合char来代表一个控制键. 其中^就是键^本身,而{char}是任意的单个字符. 可能需要在{char}前放入一个\,以防止shell将其解释为一个通配符
例如
stty可以改变的功能包括:
用stty -a会显示用户当前所有终端的设置. werase和rprnt字符有些UNIX版本未实现.
从哪里寻找可能可以使用的终端类型
可以通过搜索/etc/termcap文件内容或者通过列出在/usr/lib/terminfo目录结构中的文件名来寻找终端名,以方便地设置TERM
文本处理
分割文本
按行数分割
使用split分割
使用sed来实现
按字节数分割
使用split分割
使用dd分割
按列粘贴文本
若希望并排粘贴N个文件的内容,则可以使用paste命令
合并的数据流默认情况下使用TAB分割,但是可以用-d选项来指定分隔符。
匹配连接两个文本的内容
join会在文件中搜索某些列,找到相互匹配的行之后,它会在该列的位置上把两列文本粘帖在一起
默认join会以第一列的内容进行匹配,也可以使用-1 FIELD和-2 FIELD来指定file1和file2的FIELD列
uniq用来删除以排序的文件中相邻文本行的重复内容
需要注意的是:
uniq file1 file2
的意思是用file1的唯一行代替file2的内容
使用sort对文本进行排序
选项
sort排序规则
{TAB}12 345 678中参与第0列排序的是{TAB}12而不是12
根据长度对行进行排序
shell编程
case语句中的模式匹配
trap捕获信号量
trap "command1;command2…" sign1 sign2…
捕获到sign1,sign2…等信号后,执行command1;command2
使用getopt/getopts处理脚本的参数解析
使用set命令重新初始化脚本的参数
使用set 新参数1 新参数2…能够初始化脚本的参数。
但要注意的是,若新参数以-开头的,则shell会把它看出是自己的选项。
使用jot命令产生数组
jot 要产生多少个参数 [起始参数值 结束参数值]
使用exec可以重定向shell脚本的IO
exec command会执行comand来代替当前shell,它常常用于shell脚本的最后一个命令.
但exec也可以用来重定向当前shell脚本的IO,例如
上面命令使得当前shell中所有命令的标准输入来自于文件formfile
:操作符
:操作符会计算它的参数值,并返回0退出状态,它可以用来
!的原理
!的原理实际是将脚本名作为参数拼接到#!后面的程序后面来运行该脚本的. 例如
则在直接执行该脚本时,内核实际上执行的是
这也是为什么用awk作为#!行的命令解释程序时,需要加-f的原因,因为-f表示用从文件中读取脚本.
因此使用#!/bin/cp可以制作自复制脚本. 将它放到名为zap的文件中,运行zap zup,则会有一份zup的自拷贝
另外,需要注意,内核不会去搜索PATH路径,因此#!中的解释程序必须使用绝对路径.
如何将捕获到的信号传递给子进程?
使用trap : sign1 sign2…
会忽略信号,向子进程传递信号
参数替换操作符
为了保护密码而关闭回显
使用stty -echo就能关闭回显,这样用户的输入就不会显示在屏幕上了
sh<file与sh file有时候那么区别?
sh<file若file中有无法进行read操作
创建锁文件,防止多个进程同时操作
掩码只会在文件存在时起作用.如果文件尚不存在,掩码就不会应用于它. 基于该特性,可以创建一个锁文件
事实上,可以通过如下命令来创建模式为000的文件