JackieMium / my_blog

在 Issues 中建立的个人博客
GNU General Public License v3.0
31 stars 12 forks source link

Shell 下字符串取子集和重定向 #15

Open JackieMium opened 6 years ago

JackieMium commented 6 years ago

screenshot_2018-06-15_10-22-22

最近处理数据经常需要取某个字符串一部分用来重命名的情况,比如 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 中有三种标准输入输出,它们分别是STDINSTDOUTSTDERR,分别对应的数字是012

由于STDOUTSTDERR都会默认显示在终端上,为了区分二者的信息,就有了编号1表示STDOUT2表示STDERR

搞清楚标准输入输出和错误输出再来看具体的命令形式就简单多了:

  1. 终端执行 $ command 后,默认情况下,执行结果STDOUT作为标准输出和STDERR错误输出(如果有的话)都直接被在终端打印出来,或者说终端直接显示出来。

  2. 终端执行$ command 1> out.txt 2> err.txt 后,会将STDOUTSTDERR分别存放至out.txterr.txt 中。该命令也可以写成下面三种形式

    $ command > out.txt 2> err.txt
    $ command 2> err.txt >out.txt
    $ command 2> err.txt 1> out.txt

    即顺序谁前谁后无所谓,而且默认输出就是 1,所以它是可以直接省略掉的。

  3. $ command > file 2>&1 命令里, & 并不是后台或者 AND 的意思,放在>后面的&,表示重定向的目标不是一个普通文件,而是一个文件描述符,是标准输入输出这些。所以2> 1 代表将 STDERR 即错误输出重定向到当前路径下文件名为 1普通文件 中,而 2> &1 却是代表将重定向到标准输出。而由于标准输出已经被重定向到 file 中,因此最终的结果为标准输出和错误输出都被重定向到 file 中。 &> file 是一种特殊的用法,也可以写成 >& file,二者的意思完全相同,都等价于 >file 2> &1,这里&> 或者 >& 都应该视作整体,分开没有单独的含义。