my_blog
my_blog copied to clipboard
Shell 下字符串取子集和重定向
最近处理数据经常需要取某个字符串一部分用来重命名的情况,比如 sample1.fastq.gz
比对到基因组想要取出来 sample1
用来命名生成的 sam
文件或者 log,PC 跑起来太慢 log 不能盯着看结果太多又必须要求重定向。每次都要查一下取子集和输出和错误怎么重定向,自己都烦了,干脆写在这儿了。
字符串取子集
Shell 里字符串取子集用到 ${}
这样的命令形式。下面通过例子来说明。
我们先定义了一一个变量:
file=/dir1/dir2/dir3/my.file.txt
下面就用 ${ }
分別获得不同的值:
${file#*/}
:拿掉第一个 /
及其左边的字串:dir1/dir2/dir3/my.file.txt
${file##*/}
:拿掉最后一个 /
及其左边的字串:my.file.txt
${file#*.}
:拿掉第一个 .
及其左边的字串:file.txt
${file##*.}
:拿掉最后一个.
及其左边的字串:txt
${file%/*}
:拿掉最后一个 /
及其右邊的字串:/dir1/dir2/dir3
${file%%/*}
:拿掉第一个 /
及其右边的字串:(空值)
${file%.*}
:拿掉最后一个 .
及其右边的字串:/dir1/dir2/dir3/my.file
${file%%.*}
:拿掉第一个 .
及其右边的字串:/dir1/dir2/dir3/my
关于 %
和 #
谁是左谁是右,简单的记法就是看这两个键位在普通 QWERTY 键盘上的位置:
#
是去掉左边(在键盘上 #
在 %
的左边)
%
是去掉右边(在键盘上 %
在 #
的右边)
符号用一次是最小匹配﹔两个连用就是最大匹配。
${file:0:5}
:提取最左边的 5 个字节:/dir1
${file:5:5}
:提取第 5 个字节右边的连续 5 个字节:/dir2
对变量里的的字串作替换:
${file/dir/path}
:把第一个 dir
替换为 path
:/path1/dir2/dir3/my.file.txt
${file//dir/path}
:把全部 dir
替换为 path
:/path1/path2/path3/my.file.txt
重定向
Linux 中有三种标准输入输出,它们分别是STDIN
,STDOUT
,STDERR
,分别对应的数字是0
,1
,2
。
-
STDIN
是标准输入,默认从键盘读取信息; -
STDOUT
是标准输出,默认将输出结果输出至终端; -
STDERR
是标准错误,默认将输出结果输出至终端。
由于STDOUT
与STDERR
都会默认显示在终端上,为了区分二者的信息,就有了编号1
表示STDOUT
,2
表示STDERR
。
搞清楚标准输入输出和错误输出再来看具体的命令形式就简单多了:
- 终端执行
$ command
后,默认情况下,执行结果STDOUT
作为标准输出和STDERR
错误输出(如果有的话)都直接被在终端打印出来,或者说终端直接显示出来。 - 终端执行
$ command 1> out.txt 2> err.txt
后,会将STDOUT
与STDERR
分别存放至out.txt
和err.txt
中。该命令也可以写成下面三种形式
$ command > out.txt 2> err.txt
$ command 2> err.txt >out.txt
$ command 2> err.txt 1> out.txt
即顺序谁前谁后无所谓,而且默认输出就是 1
,所以它是可以直接省略掉的。
-
$ command > file 2>&1
命令里,&
并不是后台或者 AND 的意思,放在>
后面的&
,表示重定向的目标不是一个普通文件,而是一个文件描述符
,是标准输入输出这些。所以2> 1
代表将STDERR
即错误输出重定向到当前路径下文件名为1
的普通文件
中,而2> &1
却是代表将重定向到标准输出。而由于标准输出已经被重定向到file
中,因此最终的结果为标准输出和错误输出都被重定向到file
中。&> file
是一种特殊的用法,也可以写成>& file
,二者的意思完全相同,都等价于>file 2> &1
,这里&>
或者>&
都应该视作整体,分开没有单独的含义。