管道指令如何配合mv进行特殊文件的批量剪切
本次任务:将某一目录下所有的显式文件(不包括文件夹)全部移到指定目录下。
情景:
- 在root的home目录(~或/root)下有这些文件和目录(文件夹)
[root@localhost ~]# ll
total 132
-rw-------. 1 root root 2596 Apr 18 17:00 anaconda-ks.cfg
-rw-r--r--. 1 root root 392 Jun 2 21:54 another
-rw-r--r--. 1 root root 176 Sep 15 2007 bashrc
-rw-r--r--. 1 root root 22 Jun 7 15:57 catfile
-rw-r--r--. 1 root root 2872 Jun 7 18:37 col.man
-rw-r--r--. 1 root root 50 Jun 2 21:55 fiveten
drwxr-xr-x. 3 root root 4096 Apr 18 17:00 home
-rw-r--r--. 1 root root 1167 Jun 7 18:20 homefile
drwxr-xr-x. 22 root root 4096 Jun 2 19:23 initrd
-rw-r--r--. 1 root root 45509 Apr 18 17:00 install.log
-rw-r--r--. 1 root root 13217 Apr 18 16:59 install.log.syslog
-rw-r--r--. 1 root root 7122 Jun 7 18:17 last.list
-rw-r--r--. 1 root root 89 Jun 9 23:14 pay.txt
-rw-r--r--. 1 root root 97 Jun 9 21:14 printf.txt
-rw-r--r--. 1 root root 650 Jun 9 20:56 regular_express.txt
-rw-r--r--. 1 root root 1167 Jun 7 15:35 rootfile
drwxr-xr-x. 2 root root 4096 Jun 14 10:54 test
- 由上面的输出可知,home,initrd,test为目录,我们要将所有除目录外的显示文件都剪切到test目录下。
方法一:
ll | grep '^-' | awk '{print $9}' | xargs -i mv {} ./test
分析:
ll(ls -l):列出当前目录下显式的文件和目录的详细信息。共有九个字段,其中第一个字段表示文档的属性,-:表示普通文件,d:表示目录文件。
|:竖线,Enter键上面的那个按键,该符号为管道,作用是管道符左边命令的输出就会作为管道符右边命令的输入。
grep '^-':提取出开头字符为‘-’的输出行。也即提取出显式普通文件,去掉目录,‘^word’表示待搜寻的字符串(word)在行首,grep按行为单位进行操作。
awk '{print $9}':该命令提取出文件的名称,通常在第九列。awk主要处理每一行的字段内的数据,默认的字段分隔符为空格键或TAB键(可能导致提取错误)。而sed主要以行为单位处理数据。awk后面接两个单引号并加上大括号 {} 来设定想要对数据进行的处理动作,并且透过 print 的功能将字段数据列出来。
xargs -i mv {} ./test:将上一个命令输出的文件名构造成参数列表,传递给mv指令使用。至此所有的除目录外的文件都剪切到test/目录中了
xargs的用法之一是构造参数列表并运行命令,即将接收的参数传递给后面的command 命令执行。由于mv,ls,cp不支持管道命令,所以可以配合xargs使用,达到相同的效果。-i -i 选项告诉 xargs 可以使用{}代替传递过来的参数, 建议使用-I(是i的大写字母I,不是数字1,也不是L的小写字母),其符合POSIX标准,由于mv的第一个参数为源文件,在这里{}的作用就是表示xargs处理后的参数传递到{}中供mv使用。所以也可写成:
[root@localhost ~]# ll | grep '^-' | awk '{print $9}' | xargs -I {} mv {} ./test
[root@localhost ~]# man xargs
-I replace-str
Replace occurrences of replace-str in the initial-arguments with
names read from standard input. Also, unquoted blanks do not
terminate input items; instead the separator is the newline
character. Implies -x and -L 1.
执行结果如下:
[root@localhost ~]# ll | grep '^-' | awk '{print $9}' | xargs -i mv {} ./test
[root@localhost ~]# ls
home initrd test
[root@localhost ~]# cd test
[root@localhost test]# ls
anaconda-ks.cfg catfile homefile last.list regular_express.txt
another col.man install.log pay.txt rootfile
bashrc fiveten install.log.syslog printf.txt[root@localhost test]# ll
total 120
-rw-------. 1 root root 2596 Apr 18 17:00 anaconda-ks.cfg
-rw-r--r--. 1 root root 392 Jun 2 21:54 another
-rw-r--r--. 1 root root 176 Sep 15 2007 bashrc
-rw-r--r--. 1 root root 22 Jun 7 15:57 catfile
-rw-r--r--. 1 root root 2872 Jun 7 18:37 col.man
-rw-r--r--. 1 root root 50 Jun 2 21:55 fiveten
-rw-r--r--. 1 root root 1167 Jun 7 18:20 homefile
-rw-r--r--. 1 root root 45509 Apr 18 17:00 install.log
-rw-r--r--. 1 root root 13217 Apr 18 16:59 install.log.syslog
-rw-r--r--. 1 root root 7122 Jun 7 18:17 last.list
-rw-r--r--. 1 root root 89 Jun 9 23:14 pay.txt
-rw-r--r--. 1 root root 97 Jun 9 21:14 printf.txt
-rw-r--r--. 1 root root 650 Jun 9 20:56 regular_express.txt
-rw-r--r--. 1 root root 1167 Jun 7 15:35 rootfile
[root@localhost test]# cd ..
[root@localhost ~]# ll
total 12
drwxr-xr-x. 3 root root 4096 Apr 18 17:00 home
drwxr-xr-x. 22 root root 4096 Jun 2 19:23 initrd
drwxr-xr-x. 2 root root 4096 Jun 14 11:43 test
由上看到所有的除目录外的文件都移到test/目录下,如此看来功能都实现了,但是……
当文档名称中间有空格怎么办呢,由于awk命令的“缺陷”:默认以空格或TAB键为空格,会产生误判,
举例:
[root@localhost ~]# touch "f ile"
[root@localhost ~]# ls
anaconda-ks.cfg col.man homefile last.list rootfile
another f ile initrd pay.txt test
bashrc fiveten install.log printf.txt
catfile home install.log.syslog regular_express.txt
[root@localhost ~]# ll | grep '^-' | awk '{print $9}' | xargs -I {} mv {} ./test
mv: cannot stat `f': No such file or directory
[root@localhost ~]# ls
f ile home initrd test
出现错误了,“f ile”文件没有被剪切过去。
解决方法:
ls -1 -F | grep -v [/$] | xargs -I {} mv {} ./test
解释:
ls -1 ,注意这里是数字1,作用是单列输出。-1 list one file per line
ls-F:根据文件、目录等信息在文件名或目录名最后给予附加数据结构,例如:
*代表可执行文件;/代表目录;=代表socket文件;|代表FIFO文件;@代表连接文件-F, --classify
append indicator (one of */=>@|) to entries[root@localhost ~]# ls -1
f ile
home
initrd
test
[root@localhost ~]# ls -F
f ile home/ initrd/ test/
[root@localhost ~]#
通过上面的一个任务熟悉了linux下管线,正规表达式,通配符,bash命令等的使用。
通配符和正规表达式的区别?