您的位置:首页 > 运维架构 > Shell

shell

2013-12-29 21:58 281 查看
在阅读以下部分前,强烈建议读者打开一个shell实验,这些都不是shell教科书里的大路货哦:)
!$
!$是一个特殊的环境变量,它代表了上一个命令的最后一个字符串。如:你可能会这样:
$mkdir mydir
$mv mydir yourdir
$cd yourdir
可以改成:
$mkdir mydir
$mv !$ yourdir
$cd !$

screen -d -m -S some_name ping my_router
后台运行一段不终止的程序,并可以随时查看它的状态。-d -m参数启动“分离”模式,-S指定了一个session的标识。可以通过-R命令来重新“挂载”一个标识的session。更多细节请参考screen用法 man screen。

‘ALT+.’ or ‘<ESC> .’
热建alt+. 或 esc+. 可以把上次命令行的参数给重复出来。
^old^new
替换前一条命令里的部分字符串。
场景:echo "wanderful",其实是想输出echo "wonderful"。只需要^a^o就行了,对很长的命令的错误拼写有很大的帮助。(陈皓注:也可以使用 !!:gs/old/new)
du -s * | sort -n | tail
列出当前目录里最大的10个文件。
:w !sudo tee %
在vi中保存一个只有root可以写的文件
date -d@1234567890
时间截转时间

> file.txt
创建一个空文件,比touch短。

在命令行前加空格,该命令不会进入history里。

echo “ls -l” | at midnight
在某个时间运行某个命令。

ps aux | sort -nk +4 | tail
列出头十个最耗内存的进程
man ascii
显示ascii码表。
场景:忘记ascii码表的时候还需要google么?尤其在天朝网络如此“顺畅”的情况下,就更麻烦在GWF多应用一次规则了,直接用本地的man ascii吧。

tail -f /path/to/file.log | sed '/^Finished: SUCCESS$/ q'
当file.log里出现Finished: SUCCESS时候就退出tail,这个命令用于实时监控并过滤log是否出现了某条记录。
ssh user@server bash < /path/to/local/script.sh
在远程机器上运行一段脚本。这条命令最大的好处就是不用把脚本拷到远程机器上。
ssh user@host cat /path/to/remotefile | diff /path/to/localfile -
比较一个远程文件和一个本地文件

4)split

如果你有一个很大的文件,你想把其分割成一些小的文件,那么这个命令就是干这件事的了。

[hchen@RHELSVR5 applebak]# ls -l largefile.tar.gz
-rw-r--r-- 1 hchen hchen 436774774 04-17 02:00 largefile.tar.gz

[hchen@RHELSVR5 applebak]# split -b 50m largefile.tar.gz LF_
[hchen@RHELSVR5]# ls -l LF_*
-rw-r--r-- 1 hchen hchen 52428800 05-10 18:34 LF_aa
-rw-r--r-- 1 hchen hchen 52428800 05-10 18:34 LF_ab
-rw-r--r-- 1 hchen hchen 52428800 05-10 18:34 LF_ac
-rw-r--r-- 1 hchen hchen 52428800 05-10 18:34 LF_ad
-rw-r--r-- 1 hchen hchen 52428800 05-10 18:34 LF_ae
-rw-r--r-- 1 hchen hchen 52428800 05-10 18:35 LF_af
-rw-r--r-- 1 hchen hchen 52428800 05-10 18:35 LF_ag
-rw-r--r-- 1 hchen hchen 52428800 05-10 18:35 LF_ah
-rw-r--r-- 1 hchen hchen 17344374 05-10 18:35 LF_ai

文件合并只需要使用简单的合并就行了,如:1 [hchen@RHELSVR5]# cat LF_* >largefile.tar.gz

6)mkfifo

熟悉Unix的人都应该知道这个是一个创建有名管道的系统调用或命令。平时,我们在命令行上使用竖线“|”把命令串起来是使用无命管道。而我们使用mkfifo则使用的是有名管道。下面是示例:

下面是创建一个有名管道:

[hchen@RHELSVR5 ~]# mkfifo /tmp/hchenpipe

[hchen@RHELSVR5 ~]# ls -l /tmp
prw-rw-r-- 1 hchen hchen 0 05-10 18:58 hchenpipe

然后,我们在一个shell中运行如下命令,这个命令不会返回,除非有人从这个有名管道中把信息读走。1 [hchen@RHELSVR5 ~]# ls -al > /tmp/hchenpipe

我们在另一个命令窗口中读取这个管道中的信息:(其会导致上一个命令返回)

[hchen@RHELSVR5 ~]# head /tmp/hchenpipe
drwx------ 8 hchen hchen 4096 05-10 18:27 .
drwxr-xr-x 7 root root 4096 03-05 00:06 ..
drwxr-xr-x 3 hchen hchen 4096 03-01 18:13 backup
-rw------- 1 hchen hchen 721 05-05 22:12 .bash_history
-rw-r--r-- 1 hchen hchen 24 02-28 22:20 .bash_logout
-rw-r--r-- 1 hchen hchen 176 02-28 22:20 .bash_profile
-rw-r--r-- 1 hchen hchen 124 02-28 22:20 .bashrc
-rw-r--r-- 1 root root 14002 03-07 00:29 index.htm
-rw-r--r-- 1 hchen hchen 31465 03-01 23:48 index.php

7)ldd

这个命令可以知道你的一个可执行文件所使用了动态链接库。如:

[hchen@RHELSVR5 ~]# ldd /usr/bin/java
linux-gate.so.1 => (0x00cd9000)
libgij.so.7rh => /usr/lib/libgij.so.7rh (0x00ed3000)
libgcj.so.7rh => /usr/lib/libgcj.so.7rh (0x00ed6000)
libpthread.so.0 => /lib/i686/nosegneg/libpthread.so.0 (0x00110000)
librt.so.1 => /lib/i686/nosegneg/librt.so.1 (0x009c8000)
libdl.so.2 => /lib/libdl.so.2 (0x008b5000)
libz.so.1 => /usr/lib/libz.so.1 (0x00bee000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00aa7000)
libc.so.6 => /lib/i686/nosegneg/libc.so.6 (0x0022f000)
libm.so.6 => /lib/i686/nosegneg/libm.so.6 (0x00127000)
/lib/ld-linux.so.2 (0x00214000)

8)col

这个命令可以让你把man文件转成纯文本文件。如下示例:

# PAGER=cat
# man less | col -b > less.txt

10)lsof

可以列出打开了的文件。

[root@RHELSVR5 ~]# lsof | grep TCP
httpd 548 apache 4u IPv6 14300967 TCP *:http (LISTEN)
httpd 548 apache 6u IPv6 14300972 TCP *:https (LISTEN)
httpd 561 apache 4u IPv6 14300967 TCP *:http (LISTEN)
httpd 561 apache 6u IPv6 14300972 TCP *:https (LISTEN)
sshd 1764 root 3u IPv6 4993 TCP *:ssh (LISTEN)
tcpserver 8965 root 3u IPv4 153795500 TCP *:pop3 (LISTEN)
mysqld 10202 mysql 10u IPv4 73819697 TCP *:mysql (LISTEN)
sshd 10735 root 3u IPv6 160731956 TCP 210.51.0.232:ssh->123.117.239.68:31810 (ESTABLISHED)
sshd 10767 hchen 3u IPv6 160731956 TCP 210.51.0.232:ssh->123.117.239.68:31810 (ESTABLISHED)
vsftpd 11095 root 3u IPv4 152157957 TCP *:ftp (LISTEN)

xargs & parallel

Executes tasks from input (even multithread).

xargs 是一个比较古老的命令,有简单的并行功能,这个不说了。对于GNU parallel ( online manpage )来说,它不仅能够处理本机上多执行绪,还能分散至远端电脑协助处理。而使用GNU parallel前,要先确定本机有安装GNU parallel / ssh / rsync,远端电脑也要安装ssh。

cowsay & sl

cowsay 不说了,如下所示,哈哈哈。还有xcowsay,你可以自己搜一搜。

sl是什么?ls?,呵呵,你会经常把ls 打成sl吗?如果是的话,这个东西可以让你娱乐一下,你会看到一辆火车呼啸而过~~,相当拉风。你可以使用sudo apt-get install sl 安装。

最后,再介绍一个命令中linuxlogo,你可以使用 sudo apt-get install linuxlogo来安装,然后,就可以使用linuxlogo -L
来看一下各种Linux的logo了

EXAMPLES
find /tmp -name core -type f -print | xargs /bin/rm -f

Find files named core in or below the directory /tmp and delete them. Note that this will work incorrectly if there are any filenames containing newlines or spaces.

find /tmp -name core -type f -print0 | xargs -0 /bin/rm -f

Find files named core in or below the directory /tmp and delete them, processing filenames in such a way that file or directory names containing spaces or newlines are correctly handled.

find /tmp -depth -name core -type f -delete

Find files named core in or below the directory /tmp and delete them, but more efficiently than in the previous example (because we avoid the need to use fork(2) and exec(2) to launch rm and
we don't need the extra xargs process).

cut -d: -f1 < /etc/passwd | sort | xargs echo

Generates a compact listing of all the users on the system.

wildcard-通配符

正则表达式的模式与文件名的通配符是不同的,前者中“.*”匹配任意字符字符串,“*”在后者中匹配任何的字符字符串;

quoting---引用

一般来说,使用单引号的时机是希望完全不处理的地方,否则,当你希望将多个单词视为单一字符串,但又需要shell为你做些事情时,请使用双引号;

shell命令查找次序是先找特殊内建命令,再找shell函数,接下来是一般内建命令,最后为PATH变量内所列目录下找到的外部命令;

.(点号)在shell中用法:读取与执行包含在文件中的命令:. my_funcs

局部变量:
1.定义变量
str="linux"
2.输出变量
echo $str
echo ${str}ing
3.删除变量
unset str
4.查看变量
set #查看局部和全局变量

全局变量:
1.查看全局变量
env
2.把局部变量变成全局变量
export str
3.常用全局变量
PS1='[\u@\h \W]\$'
#改变命令提示符

shell 中数学运算
expr 1 + 2
expr 2 - 1
expr 2 / 1
expr 2 \* 2
数字自增:
num=`expr $num + 1`

let num++

ForIn 循环使用:
for loop in a b c
do
  echo $loop
done

For 循环使用:
for((i=0;i<5;i++))
do
  echo $i
done

While 语句使用:
while [ $num -le 5 ]
do
  echo "aaaa"
done

While 死循环使用:
while :
do
  echo "dead"
done

该命令(.)和 source 是等价的。----Bash reference

递归查看目录
1)tree
2)ls -lR

gz 压缩:
1.压缩
tar czf file.tar.gz file
2.解压缩
tar xzf file.tar.gz
3.把压缩包解压到指定的目录下
tar xzf file.tar.gz -C /mnt
4.查看压缩包内容
tar tf file.tar.gz

bz2 压缩:
1.压缩
tar cjf file.tar.bz2 file
2.解压缩
tar xjf file.tar.bz2
3.查看压缩包内容
tar tf file.tar.bz2

bai@bbox:~/test$ date
2014年 01月 02日 星期四 19:58:40 CST
bai@bbox:~/test$ date "+%Y-%m-%d %H:%M:%S"
2014-01-02 19:59:10

tail -f /etc/passwd #实时跟踪文件的后十行

让光盘开机自动挂载到/media 下
vi /etc/fstab
/dev/cdrom /media iso9660 defaults 0 0

rsync -a web/ /mnt/
#把 web 下的所有文件拷贝到/mnt 下
rsync -a web /mnt
#把 web 目录拷贝到/mnt 下

userdel -r user1
#如果 userdel user1 删除,会留下用户家目录和用户邮箱

1.把用户加入组
1).usermod -g grp1 user1 #force use GROUP as new primary group
2).usermod -aG grp1 user1

-G, --groups GROUPS new list of supplementary GROUPS
-a, --append append the user to the supplemental GROUPS mentioned by the -G option without removing him/her from other groups(Use only with the -G option.)

3).gpasswd -a user1 grp1
#把用户 user1 加入组 grp1
2.把用户从组删除
1).gpasswd -d user1 grp1
#把用户 user1 从 grp1 组中删除

umask 文件权限掩码,由它决定文件夹权限是 755,文件权限是 644

kill -9 pid
#强制杀掉一个进程号
kill -2 pid
#建议退出,ctrl+c
kill -1 pid
#建议进程重新加载自己的配置文件

创建计划任务:
crontab -e
查看计划任务:
crontab -l
删除计划任务:
crontab -r

关于 crontab 语法:
1)时间
2)执行命令
3.时间
***** 分 时 日 月 周
30 17 * * * 每天下午 5:30
00 00 * * * 每天晚上 00:00
00 00 * * 1-5 周一到周五的每天晚上 00:00
*/5 * * * * 每隔 5 分钟
00 00 * * 1,3,5 周一、周三和周五的晚上 00:00
4.命令
全用全路径

respawn:如果相应的进程还不存在,那么init就启动该进程,同时不等待该进程的结束就继续扫描/etc/inittab文件;当该进程死亡时,init将重新启动该进程。如果相应的进程已经存在,那么init将忽略该登记项并继续扫描/etc/inittab文件。

respawn 不管何时终止都重新启动进程

与用户有关的三个文件
/etc/passwd
#保存用户属性
/etc/group
#用户所属组
/etc/shadow
#用户密码,grub-md5-crypt 加密方法,把密码保存在/etc/shadow 中的第二列
8.锁定用户
usermod -L user1,即把/etc/shadow 中的密码前加了个!,即禁用本用户
9.解锁用户
usermod -U user1
10.用户分类
超级管理员-root,uid 为 0
系统用户 uid 为 1-499
普通用户 uid 为 500->

tee 命令接收标准输入并将数据输出到标准输出和一个文件内。

shell 内部命令:不产生子进程
1) eval:在 shell 程序中,利用变量的值来构建命令
A=ls
B= ‘ | wc -w’
eval $A$B
2) exec:转去执行 exec 后命令,不建立新进程,也不返回到当前的执行过程,相当于 go to 语句。
3) read:从标准输入设备(键盘)读入一行,并把读入的字依次赋给各变量,所有剩余的字赋给
最后一个变量。

4) shift:使命令行参数向左移动一位,并使记录参数总数的变量$#减 1

5)wait:等待当前进程所有子进程结束,若 wait 后跟参数 n,则等待进程 n 结束。

6) trap:中断处理命令
trap 命令表 中断信号表
#cat trapfile
trap echo ‘ This is INT 2’ 2
trap echo ‘ This is INT 3’ 3
for I in /bin /bin/usr
do
echo $I
done

下面程序实现 scan:扫描当前目录下的每一个子目录,并执行用户提交的命令:
d=`pwd`
for i in *
do
if test –d $d/$i
then
cd $d/$i
while echo “$i:”
trap exit 2
read x
do trap : 2 ; eval $x; done
fi
done
7)点命令 .
在 bsh 利用 . 命令执行一个命令时,不创建子进程。

cut -b colnum file: 指定欲显示的文件内容范围,并将它们输出到标准输出设备比如:输
出每行第 5 个到第 9 个字符 cut -b5-9 file.txt

在向程序传递任何参数之前,程序会扩展通配符和变量。
这里所谓扩展的意思是程序会把通
配符(比如*)替换成合适的文件名,它变量替换成变量值。
为了防 止程序作这种替换,您可以
使用引号:让我们来看一个例子,假设在当前目录下有一些文件,两个 jpg 文件, mail.jpg
和 tux.jpg。
#!/bin/sh
echo *.jpg
这将打印出"mail.jpg tux.jpg"的结果。
引号 (单引号和双引号) 将防止这种通配符扩展:
#!/bin/sh
echo "*.jpg"
echo '*.jpg'
这将打印"*.jpg" 两次。
单引号更严格一些。
它可以防止任何变量扩展。
双引号可以防止通配符扩展但允许变量扩展。

#!/bin/sh
echo $SHELL
echo "$SHELL"
echo '$SHELL'
运行结果为:
/bin/bash
/bin/bash
$SHELL
最后,还有一种防止这种扩展的方法,那就是使用转义字符——反斜杆:
echo \*.jpg
echo \$SHELL
这将输出:
*.jpg
$SHELL

case 值 in
模式1)
命令1
...
;;
模式2)
命令2
...
;;
esac

模式部分可能包括元字符,与在命令行文件扩展名例子中使用过的匹配模式类型相同,即:
* 任意字符。
? 任意单字符。
[..] 类或范围中任意字符。

命令替换形式 $(cat 文件名) 可以用与其等价但速度更快的 $(< 文件名) 来取代。 for i in $(</proc/cmdline)

${参数:−单词}
如果参数没有设置或者为空,则替换为单词;否则替换为参数的值。
${参数:=单词}
如果参数没有设置或者为空,则把扩展后的单词赋给参数,然后替换为参数的值。对位置参数和特殊参数,不可以这样进行赋值。
${参数:?单词}
如果参数没有设置或者为空,就把扩展后的单词 (如果没有给出单词,则代之以一条大意相同的信息)写到标准错误输出中。如果当前的shell是交互式的,退出shell。否则,替换为参数的值。
${参数:+单词}
如果参数没有设置或者为空,不进行任何替换;否则,替换为扩展后的单词。

while read LINE

do

  echo $LINE

done < names.file

read从标准输入或者-u选项指定的文件描述符参数中读取一行文本,并把第一个单词赋值给第一个名称,把第二个单词赋值给第二个名称,依此类推;剩余的单词连同分隔符一起赋值给最后一个名称。如果从输入流中读取的单词数比名称少,就把空值赋值给剩余的名称。IFS 变量中的字符用来把文本行分隔成单词。 Shell 脚本中有个变量叫 IFS(Internal Field Seprator) ,内部域分隔符。完整定义是The shell uses the value stored in IFS, which is the space, tab, and newline characters by default, to delimit words for the read and set commands, when parsing output from command substitution, and when performing variable substitution.

所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分.

shell 函数是在当前的shell环境中执行的,而不是创建新的进程来执行.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: