一、linux中的常用符号
* | 代表任意字符串 |
? | 代表任意字符 |
/ | 代表根目录或作为路径间隔符使用 |
\ | 转义字符。 |
\ |
续行符。可以使用续行符将一个命令行分写在多行上 |
$ | 变量值置换,如:$PATH表示环境变量PATH的值 env显示所有系统环境变量 export修改系统环境变量 |
' | 在’…'中间的字符都会被当做普通字符处理 |
"" | 在’’…’'中间的字符会被当做文字处理并允许变量值置换 |
` | 命令替换,置换`…`中命令的执行结果 |
< | 输入重定向字符 |
> | 输出重定向字符 |
| | 管道字符 |
& | 后台执行字符。在一个命令之后加上字符“&”,该命令就会以后台方式执行 |
; | 按照顺序执行的多个命令 |
() | 在子Shell中执行命令 |
{} | 在当前Shell中执行命令 |
! | 执行命令历史记录中的命令 |
~ | 代表登录用户的宿主目录(自家目录) |
二、历史记录
linux系统在shell中保留了用户键入的每一个命令的历史记录,并且提供了很多种方法让用户通过历史记录找到曾经使用过的命令,并且调用这个历史记录的命令。
[root@zuolaoshi ~]# history
1 ifconfig
2 ip ad sh
3 free -h
4 df -h
语法 | 替换 |
---|---|
!! | 前一个命令 |
!n | 命令号n |
!-n | 倒数第n个命令 |
!cmd | 最后用来启动cmd的命令 |
与历史记录相关的文件和变量
[root@zuolaoshi ~]# echo $HISTFILE
/root/.bash_history
#用户的历史记录保存的位置
[root@zuolaoshi ~]# echo $HISTFILESIZE
1000
#启动时,从历史记录中读取的记录条数
[root@zuolaoshi ~]# echo $HISTSIZE
1000
#退出时,被写入历史记录的最大条数
历史记录技巧
esc+./alt+. 调用上一条命令的最后一部分内容
ctrl+r 在历史记录中搜索给出关键字的命令
三、标准输入、标准输出、标准错误
在linux系统中,大多数时候我们从键盘读取输入,在终端显示输出,而我们在键盘中输入的内容,多数都是执行命令,这些命令属于终端程序,除了终端程序还有图形程序和屏幕程序(如vim),不管是哪一种程序都会涉及到输入,输出,错误,多数情况下,我们在键盘输入信息,在显示器查看信息(正确的信息和错误的信息),这些输入的信息我们称之为标准输入(可以用0表示),输出的信息我们称之为标准输出(可以用1表示),而错误的信息(可以用2表示),我们称之为标准错误。在日常使用中我们除了可以使用键盘输入信息,从显示器读取信息之外,还可以指定程序从键盘以外的地方读取需要输入的内容,也可以让程序将信息输出到显示器以外的地方。
重定向输入和输出
#重定向输出
[root@zuolaoshi ~]# mkdir a
[root@zuolaoshi ~]# cd a
[root@zuolaoshi a]# mkdir aa ab ac
[root@zuolaoshi a]# cd aa
[root@zuolaoshi aa]# touch bb bc bd
[root@zuolaoshi ~]# ls a/ > test
[root@zuolaoshi ~]# cat test
aa
ab
ac
[root@zuolaoshi ~]# ls a/aa/ >> test
[root@zuolaoshi ~]# cat test
aa
ab
ac
bb
bc
bd
>覆盖
>>追加
#重定向输入
[root@zuolaoshi ~]# wc -l test
6 hello
[root@zuolaoshi ~]# wc -l < test
6
注意:第一个例子,会输出文件名;第二个不会,因为它仅仅知道从标准输入读取内容。
我们知道标准输入可以用0来表示,标准输出可以用1来表示,标准错误可以用2来表示,而有些时候这些输出的信息中即包含了正确的信息,也包含了错误的信息,如:
[root@zuolaoshi ~]# ls /etc/rc.d/
init.d rc0.d rc1.d rc2.d rc3.d rc4.d rc5.d rc6.d rc.local
[root@zuolaoshi ~]# head -1 /etc/rc.d/*
==> /etc/rc.d/init.d <==
head: 读取'/etc/rc.d/init.d' 时出错: 是一个目录
==> /etc/rc.d/rc0.d <==
head: 读取'/etc/rc.d/rc0.d' 时出错: 是一个目录
==> /etc/rc.d/rc1.d <==
head: 读取'/etc/rc.d/rc1.d' 时出错: 是一个目录
==> /etc/rc.d/rc2.d <==
head: 读取'/etc/rc.d/rc2.d' 时出错: 是一个目录
==> /etc/rc.d/rc3.d <==
head: 读取'/etc/rc.d/rc3.d' 时出错: 是一个目录
==> /etc/rc.d/rc4.d <==
head: 读取'/etc/rc.d/rc4.d' 时出错: 是一个目录
==> /etc/rc.d/rc5.d <==
head: 读取'/etc/rc.d/rc5.d' 时出错: 是一个目录
==> /etc/rc.d/rc6.d <==
head: 读取'/etc/rc.d/rc6.d' 时出错: 是一个目录
==> /etc/rc.d/rc.local <==
#!/bin/bash
我们通过ls命令查看/etc/rc.d这个目录的时候,我们发现,这个目录中即有目录,也有文件,而当我们使用“head -1”命令去查看文件的第一行内容的时候, 很显然目录是无法查看第一行的,这时就会有报错,当我想把这些信息都写入到一个指定的文件中而不想看到这些内容我该如何去做?
[root@zuolaoshi ~]# head -1 /etc/rc.d/* > test
head: 读取'/etc/rc.d/init.d' 时出错: 是一个目录
head: 读取'/etc/rc.d/rc0.d' 时出错: 是一个目录
head: 读取'/etc/rc.d/rc1.d' 时出错: 是一个目录
head: 读取'/etc/rc.d/rc2.d' 时出错: 是一个目录
head: 读取'/etc/rc.d/rc3.d' 时出错: 是一个目录
head: 读取'/etc/rc.d/rc4.d' 时出错: 是一个目录
head: 读取'/etc/rc.d/rc5.d' 时出错: 是一个目录
head: 读取'/etc/rc.d/rc6.d' 时出错: 是一个目录
[root@zuolaoshi ~]# cat test
==> /etc/rc.d/init.d <==
==> /etc/rc.d/rc0.d <==
==> /etc/rc.d/rc1.d <==
==> /etc/rc.d/rc2.d <==
==> /etc/rc.d/rc3.d <==
==> /etc/rc.d/rc4.d <==
==> /etc/rc.d/rc5.d <==
==> /etc/rc.d/rc6.d <==
==> /etc/rc.d/rc.local <==
#!/bin/bash
我们可以利用之前的>将输出的信息重定向到一个指定的文件,但是仍然会收到错误提示,这是为什么呢?因为在linux当中正确的输出和错误的输出实际上是两种数据流,默认情况下这两种数据流都会在显示器上打印出来,而我们使用的>相当于1>,也就是将正确的信息写入到了test文件中,错误的信息依旧会看到。利用前面的提到0,1,2这三个数字,我们可以这样做
[root@zuolaoshi ~]# head -1 /etc/rc.d/* > test 2> test.err
[root@zuolaoshi ~]# cat test
==> /etc/rc.d/init.d <==
==> /etc/rc.d/rc0.d <==
==> /etc/rc.d/rc1.d <==
==> /etc/rc.d/rc2.d <==
==> /etc/rc.d/rc3.d <==
==> /etc/rc.d/rc4.d <==
==> /etc/rc.d/rc5.d <==
==> /etc/rc.d/rc6.d <==
==> /etc/rc.d/rc.local <==
#!/bin/bash
[root@zuolaoshi ~]# cat test.err
head: 读取'/etc/rc.d/init.d' 时出错: 是一个目录
head: 读取'/etc/rc.d/rc0.d' 时出错: 是一个目录
head: 读取'/etc/rc.d/rc1.d' 时出错: 是一个目录
head: 读取'/etc/rc.d/rc2.d' 时出错: 是一个目录
head: 读取'/etc/rc.d/rc3.d' 时出错: 是一个目录
head: 读取'/etc/rc.d/rc4.d' 时出错: 是一个目录
head: 读取'/etc/rc.d/rc5.d' 时出错: 是一个目录
head: 读取'/etc/rc.d/rc6.d' 时出错: 是一个目录
但是这依然是两个文件,能不能将这些信息都写入到一个文件中呢?
[root@zuolaoshi ~]# head -1 /etc/rc.d/* > test.both 2>&1
[root@zuolaoshi ~]# cat test.both
==> /etc/rc.d/init.d <==
head: 读取'/etc/rc.d/init.d' 时出错: 是一个目录
==> /etc/rc.d/rc0.d <==
head: 读取'/etc/rc.d/rc0.d' 时出错: 是一个目录
==> /etc/rc.d/rc1.d <==
head: 读取'/etc/rc.d/rc1.d' 时出错: 是一个目录
==> /etc/rc.d/rc2.d <==
head: 读取'/etc/rc.d/rc2.d' 时出错: 是一个目录
==> /etc/rc.d/rc3.d <==
head: 读取'/etc/rc.d/rc3.d' 时出错: 是一个目录
==> /etc/rc.d/rc4.d <==
head: 读取'/etc/rc.d/rc4.d' 时出错: 是一个目录
==> /etc/rc.d/rc5.d <==
head: 读取'/etc/rc.d/rc5.d' 时出错: 是一个目录
==> /etc/rc.d/rc6.d <==
head: 读取'/etc/rc.d/rc6.d' 时出错: 是一个目录
==> /etc/rc.d/rc.local <==
#!/bin/bash
或者
[root@zuolaoshi ~]# head -1 /etc/rc.d/* >& test.both1
[root@zuolaoshi ~]# cat test.both1
==> /etc/rc.d/init.d <==
head: 读取'/etc/rc.d/init.d' 时出错: 是一个目录
==> /etc/rc.d/rc0.d <==
head: 读取'/etc/rc.d/rc0.d' 时出错: 是一个目录
==> /etc/rc.d/rc1.d <==
head: 读取'/etc/rc.d/rc1.d' 时出错: 是一个目录
==> /etc/rc.d/rc2.d <==
head: 读取'/etc/rc.d/rc2.d' 时出错: 是一个目录
==> /etc/rc.d/rc3.d <==
head: 读取'/etc/rc.d/rc3.d' 时出错: 是一个目录
==> /etc/rc.d/rc4.d <==
head: 读取'/etc/rc.d/rc4.d' 时出错: 是一个目录
==> /etc/rc.d/rc5.d <==
head: 读取'/etc/rc.d/rc5.d' 时出错: 是一个目录
==> /etc/rc.d/rc6.d <==
head: 读取'/etc/rc.d/rc6.d' 时出错: 是一个目录
==> /etc/rc.d/rc.local <==
#!/bin/bash
这两种使用方式都是告诉shell将错误信息写入到正确信息所写入的文件中。
如果这些错误信息是我们早就知道的,并且还不想看到的呢?
[root@zuolaoshi ~]# head -1 /etc/rc.d/* 2> /dev/null
==> /etc/rc.d/init.d <==
==> /etc/rc.d/rc0.d <==
==> /etc/rc.d/rc1.d <==
==> /etc/rc.d/rc2.d <==
==> /etc/rc.d/rc3.d <==
==> /etc/rc.d/rc4.d <==
==> /etc/rc.d/rc5.d <==
==> /etc/rc.d/rc6.d <==
==> /etc/rc.d/rc.local <==
#!/bin/bash
/dev/null:表示的是一个黑洞,通常用于丢弃不需要的数据输出
综上所述针对于输入输出重定向与合并的用法有
语法 | 作用 |
---|---|
cmd < file | 从file重定向标准输入 |
cmd > file | 把标准输出重定向到file中,如果file存在的话,覆盖(损坏)它 |
cmd>>file | 把标准输出重定向到file中,如果file存在,附加给它 |
cmd 2>file | 把标准错误重定向到file,如果file 存在,覆盖(损坏)它 |
cmd 2>> file | 把标准错误重定向到file中,如果file 存在,附加给他 |
cmd>file 2>&1 | 合并标准输出和标准错误,并且重定向到file中(可移植的语法) |
cmd >& file | 合并标准输出和标准错误,并且重定向到file中(方便的语法) |
四、管道
在前面,我们已经看到,进程的输出可以被重定向到终端显示器以外的地方,或者可以让进程从终端键盘以外的地方读取输入。一种最常用,最有力的重定向形式是把这二者结合起来,在这种形式下,一个命令的输出(标准输出)被直接“用管道输送”到另一个命令的输入(标准输入)中,从而构成了 Linux(和Unix)所谓的管道(pipe)。当两个命令用管道连接起来时,第一个进程的标准输出流被直接连接到第二个进程的标准输入序列。为了用bash创建管道,用一个垂直的小节线 | 把这两个命令连接起来。
[root@zuolaoshi ~]# pwd
/root
[root@zuolaoshi ~]# ls | grep ana
anaconda-ks.cfg
注意:从管道读数据是一次性操作,数据一旦被读,它就从管道中被抛弃,释放空间以便写更多的数据。它只能处理经由前面一个指令传出的正确输出信息,对错误信息信息没有直接处理能力。然后,传递给下一个命令,作为标准的输入。
五、数据处理常用工具
sort 对文件内容进行排序
常用命令选项
-b 忽略每行前面开始出的空格字符。
[root@zuolaoshi ~]# sort passwd
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
hello:x:1000:1000:hello:/home/hello:/bin/bash
HELLO:x:1001:1001::/home/HELLO:/bin/bash
helo:x:1002:1002::/home/helo:/bin/bash
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin
root:x:0:0:root:/root:/bin/bash
[root@zuolaoshi ~]# sort -b passwd
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
hello:x:1000:1000:hello:/home/hello:/bin/bash
HELLO:x:1001:1001::/home/HELLO:/bin/bash
helo:x:1002:1002::/home/helo:/bin/bash
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin
root:x:0:0:root:/root:/bin/bash
-c 检查文件是否已经按照顺序排序。
[root@zuolaoshi ~]# sort -c passwd
sort:passwd:2:无序: bin:x:1:1:bin:/bin:/sbin/nologin
-t 用指定的符号做为分隔符
-k 指定区间
-n 依照数值的大小排序。
-r 以相反的顺序来排序。
[root@zuolaoshi ~]# sort -t ':' -k 3 -r -n passwd
nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin
helo:x:1002:1002::/home/helo:/bin/bash
HELLO:x:1001:1001::/home/HELLO:/bin/bash
hello:x:1000:1000:hello:/home/hello:/bin/bash
dbus:x:81:81:System message bus:/:/sbin/nologin
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
root:x:0:0:root:/root:/bin/bash
或者
[root@zuolaoshi ~]# sort -t ':' -k 3rn passwd
nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin
helo:x:1002:1002::/home/helo:/bin/bash
HELLO:x:1001:1001::/home/HELLO:/bin/bash
hello:x:1000:1000:hello:/home/hello:/bin/bash
dbus:x:81:81:System message bus:/:/sbin/nologin
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
root:x:0:0:root:/root:/bin/bash
-o<输出文件> 将排序后的结果存入指定的文件。
[root@zuolaoshi ~]# sort -t ':' -k 3 -r -n passwd -o /root/passwd-sort
[root@zuolaoshi ~]# cat /root/passwd-sort
nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin
helo:x:1002:1002::/home/helo:/bin/bash
HELLO:x:1001:1001::/home/HELLO:/bin/bash
hello:x:1000:1000:hello:/home/hello:/bin/bash
dbus:x:81:81:System message bus:/:/sbin/nologin
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
root:x:0:0:root:/root:/bin/bash
uniq 数据去重
一般配合sort使用
案例文档
[root@zuolaoshi ~]# cat testuniq
192.168.98.2
192.168.98.8
192.168.98.3
192.168.98.3
192.168.98.9
192.168.98.8
192.168.98.8
192.168.98.0
192.168.98.3
常用命令选项
-c 在每列旁边显示该行重复出现的次数。
[root@zuolaoshi ~]# uniq -c testuniq
1 192.168.98.2
1 192.168.98.8
2 192.168.98.3
1 192.168.98.9
2 192.168.98.8
1 192.168.98.0
1 192.168.98.3
[root@zuolaoshi ~]# uniq -c testuniq | sort
1 192.168.98.0
1 192.168.98.2
1 192.168.98.3
1 192.168.98.8
1 192.168.98.9
2 192.168.98.3
2 192.168.98.8
-d 仅显示重复出现的行列。
[root@zuolaoshi ~]# uniq -d testuniq
192.168.98.3
192.168.98.8
-u 仅显示出一次的行列。
[root@zuolaoshi ~]# uniq -u testuniq
192.168.98.2
192.168.98.8
192.168.98.9
192.168.98.0
192.168.98.3
[root@zuolaoshi ~]# uniq -u testuniq | sort
192.168.98.0
192.168.98.2
192.168.98.3
192.168.98.8
192.168.98.9
xargs命令
xargs 是给命令传递参数的一个过滤器,也是组合多个命令的一个工具。用于一些不支持管道输入的命令如ls
案例文件
[root@zuolaoshi ~]# cat xargtest
a a a
b b b
c c c
d d d
e
f
g
h
i
j
k
l
常用命令选项
-n num 后面加列数
[root@zuolaoshi ~]# cat xargtest | xargs -n 2
a a
a b
b b
c c
c d
d d
e f
g h
i j
k l
[root@zuolaoshi ~]# cat xargtest | xargs
a a a b b b c c c d d d e f g h i j k l
-I 指定替换的字符串,并在后续的命令中用指定的字符串表示接收到的输入内容,并执行,可以用任意字符代替(不推荐有特殊含义的字符,如*等,如果使用请记得转意),一般为[]或{}
[root@zuolaoshi ~]# mkdir testx
[root@zuolaoshi ~]# find /var/ -name "*.log" | xargs -I a cp a ./testx
[root@zuolaoshi ~]# ls testx | wc -l
39
-i 类似-I,相当于固定就是使用{}来表示接收到的输入内容
[root@zuolaoshi ~]# find /var/ -name "*.log" | xargs -i cp {} ./testx
[root@zuolaoshi ~]# ls testx | wc -l
39
-d 指定分隔符
[root@zuolaoshi ~]# echo "a9b9c9d9" | xargs -d 9
a b c d