【Linux 笔记】Linux 基本操作 - 02. shell编程基础

笔记接上篇【Linux 笔记】Linux 基本操作 - 01. 系统认知-文本处理-软件安装-环境变量。笔记大部分源于生信技能树的B站视频教程【生信技能树】生信人应该这样学linux(更新至第14集),如有需要,可去欣赏原汁原味的视频讲解。

8. shell编程基础

(1) 变量

1) 环境变量

环境变量会在当前Shell和这个Shell的所有子Shell当中生效。
① 设置全局环境变量:export 变量名=变量值
② 查看环境变量:env
③ 查看变量内容:echo $变量名
④ 删除变量: unset 变量名
⑤ 常见系统预定义环境变量:HOMEPWDPATHPS1

echo $HOME   #显示主目录
echo $PWD    #显示当前工作目录
echo $PATH   #显示系统查找命令的路径
echo $PS1    #显示已设置的系统提示符变量
# \[\e[32;1m\]\u \[\e[33;1m\]\t \[\e[35;1m\]\w \n\[\e[0;40m\]$

在这里插入图片描述
PS1:

变量说明
\d显示日期,格式为 “星期 月 日”
\h显示简写主机名。如,默认主机名 “localhost”
\t显示24小时制时间,格式为 “HH:MM:SS”
\T显示12小时制时间,格式为 “HH:MM:SS”
\A显示24小时制时间,格式为 “HH:MM”
\u显示当前用户名
\w显示当前用户所在目录的完整名称
\W显示当前所在目录的最后一个目录
#执行的第几个命令
$提示符。如果是root用户会显示提示符为 “#”,如果是普通用户则会显示提示符为“$”。

例如:[root@bogon ~]# PS1="[\u@\t \w]$ " : \u:代表root;\t代表24小时制时间;\w(w小写表示绝对路径)。

2) 位置参数变量→写入到脚本文件内

echo $12  #"$1"为变量,"2"为一个字符串;故,"$12"输出为"$1"的内容加上字符串2
echo ${12} #变量"$12"
位置参数变量作用
$nn为数字,$0代表命令本身,$1-$9代表第1到第9个参数,10以上的参数需要用大括号{}包含,如${10}
$*代表命令行中所有的参数,$*把所有参数看成一个整体。
$@代表命令行中所有的参数,但$@把每个参数区分对待。
$#代表命令行中所有参数的个数。

例如:创建一个脚本 canshu.sh:写入 echo $0 echo $1 echo $2 echo $3

# 执行脚本文件:
bash canshu.sh 11 22 33 #脚本名称与参数间空格分隔
# canshu.sh echo 11 echo 22 echo 33
# echo $0:$0 代表命令本身,$1-$9 代表第一个到第九个参数。

3) 预定义变量

预定义变量作用
$?最后一次执行的命令的返回状态。如果这个变量的值为0,证明上一个命令正确执行;如果这个变量的值非0(具体返回哪一个数,由命令自己决定),则证明上一个命令执行不正确。
$$当前进程的进程号(PID)
$!后台运行的最后一个进程的进程号(PID)
cat > variable.sh
#!/bin/bash
echo "The current process is $$"  #输出当前进程的PID
#这个PID即为variable.sh脚本运行时,生成的进程PID

find /root -name hello.sh &
#使用find命令在root目录 下查找hello.sh文件
echo "The last one Daemon process is $!"
^C

cat variable.sh

bash variable.sh
#The current process is 168019
#The last one Daemon process is 168020
#hucy 16:30:58 ~/test
#find: ‘/root’: Permission denied

4) 自定义变量

用户自定义变量只在当前的Shell中生效;如果变量写入相应的配置文件,那么这个变量就会在所有的Shell中生效。
输出变量的值的格式为:echo $myvar 或者 echo ${myvar}
① 给变量赋值时,如果值包含空格,需要用单引号或者双引号包起来,否则会引起错误。
② 给变量赋值时,如果使用单引号,那么单引号里面的变量就不会解析成真正的值;双引号则可以。
③ 可以将一个命令执行的结果赋给一个变量。格式为:myvar=$(command)或者 `comand`。值得注意的是,务必要将$()${}的用途分开。
④ 变量的扩增,即将新的内容增加到变量原来的值上去。格式为"$变量名称""扩增内容"${变量}"扩增内容"
⑤ 使用export将变量变成环境变量,使得bash子进程可以使用变量。
⑥ 判断变量是否未设置,如果未设置则用-后面的内容赋值。语法为:var2=${var1-hellovar1}(若var1未设置,那么将hellovar1赋值给var2,否则将var1的值赋给var2)。需要注意的是,如果var1设置为空值了,那么也算是赋值了。
⑦ 判断变量是否未设置或者设置为空值,如果未设置或者设置为空值则用-后面的内容赋值。语法为:var2=${var1:-hellovar1}

更多用法与规则
在这里插入图片描述
注意:给变量赋值时,注意等号两端的空格问题。

(2) 参数

接收键盘输入=> read [选项] [变量名]

-p “提示信息” :在等待read输入时,输出提示信息    
-t:read命令会一直等待用户输入,使用此选项可以指定等待时间
-n字符数:read命令接受指定的字符数,就会执行
-s:隐藏输入的数据,适用于机密信息的输入

例如:

cat > stdinput.sh
#!/bin/bash
read -t 30 -p "Please input your name:" name
#提示“请输入姓名”并等待30秒,把用户的输入保存到变量name中。
echo "Name is $name"

read -s -t 30 -p "Please enter your age:" age
#年龄是隐私,用-s选项隐藏输入。
echo "Age is $age"
echo -e "\n"

read -n 1 -t 30 -p "Please select your gender[M/F]:" gender
#使用“-n l”选项只接收一个输入字符就会执行,不用回车
echo -e "\n"
echo "Sex is $gender"
^C

(3) 通配符

wildcard是一种命令行的路径扩展(path expansion)功能。在wildcard进行扩展后, 命令行会先完成重组,才会交给shell来处理。

一些常见的wildcard:

wildcard功能
*匹配0个或多个字符
?匹配任意单一字符
[list]匹配list中任意单一字符
[!list]匹配不在list中任意单一字符
{string1,string2,...}匹配string1或者stsring2或者(…)中其一字符串
a*b     # a与b之间可以有任意个字符(0个或多个),如aabcb, axyzb, a012b,ab等。
a?b     # a与b之间只能有一个字符,但该字符可以任意字符,如 aab, abb, acb, azb等。
a[xyz]b   # a与b之间只能有一个字符,但这个字符只能是x或者y或者z,如:axb, ayb, azb这三个。
a[!0-9]b  # a与b之间只能有一个字符,但这个字符不能是阿拉伯数字,如aab,ayb,a-b等。
a{abc,xyz,123}b   # a与b之间只能是abc或者xyz或者123这三个字串之一,扩展后是aabcb,axyzb,a123b。 

(4) 标准头文件

#!/bin/bash
## Author:
## Address:
## E-mail:
## Some demo
## ……

set -e
# Function for script description and usage
usage()
{
cat <<EOF >&2
Usage:
}

# 查看系统预设的shell
cat /etc/shells

(5) 变量替换

在bash shell中, **$()**与 `` (反引号)都是用来做命令替换(command substitution)的。

A=BCD
A=${A}E

A=ls     #命令
$A
${A}

B=la     #参数
C=/tmp   #目录

$A -$B $C  #即 ls -la /tmp
echo $A -$B $C

echo the last sunday is $(date -d "last sunday" +%Y-%m-%d)
echo the last sunday is `date -d "last sunday" +%Y-%m-%d`

(6) 循环

for 变量名 in 列表; do 循环体; done
while CONDITION; do 循环体; done
until CONDITION; do 循环体; done

# 借助echo来确保,循环正确
for i in a.txt b.txt n.txt; do echo $i; done # 文件不多,手动放在in后,用空格分开
for i in `seq 1 9`; do echo SRR250${i}; done # 文件名为数字顺序,用seq命令生成连续数据,引用命令需要``
for i in `ls data/*.txt`; do echo $i; done  # 匹配某类文件作为输入
for i in $(cat .*txt) ;do echo $i; done     # 匹配某类文件作为输入
for i in `cat list.txt`; do echo $i; done   # 使用文本源为输入列表
for i in `cat list.txt | cut -f 1`; do echo $i; done  #指定某列作为输入文件名

plot_heatmap.sh -i data/${i} -o heatmap/${i}.pdf
ls $(pwd)/SRR* | while read id;do echo $id `basename $id`;done
for id in $(ls $(pwd)/SRR*) ;do echo $id `basename $id`;done

在这里插入图片描述
注:basename #去除路径等,只剩基本文件名。

(7) 重定向

谈到 I/O redirection,不妨先认识一下File Descriptor (fd,文件描述符)。在 shell 的进程中,最常使用的 fd 有三个,分别为:

  • 0: standard Input (STDIN)
  • 1: standard output (STDOUT)
  • 2: standard Error output (STDERR)

在标准情况下,这些 fd 分别跟如下设备 (device) 关联:

  • stdin(0): keyboard
  • stdout(1): monitor
  • stderr(2): monitor

Tips: linux 中的文件描述符 (fd) 用整数表示。 linux 中任何一个进程都默认打开三个文件, 这三个文件对应的文件描述符分别是:0, 1, 2; 即 stdin, stdout, stderr。

<来改变输入的数据通道 (stdin),使之从指定的文件读进。用>来改变输出的数据通道 (stdout,stderr), 使之输出到指定的文件。严格来说,<符号之前需要指定一个 fd 的 (之前不能有空白),但因为 0 是<的预设值,因此,<0<是一样的 。

  • 标准输入:0<
  • 标准输出:1> #改变 stdout 的输出通道;
  • 标准错误:2> #改变 stderr 的输出通道;

<<是所谓的here document,它可以让我们输入一段文本,直到读到<< 后指定的字符串结束。

cat <<EOF>tmp.txt
first line here
second line here
third line here
EOF #end of file: 读到此字符串便结束,无需Ctrl+C

cat tmp.txt
#first line here
#second line here
#third line here

2>&1 #将stderr并进stdout输出。
1>&2 或者 >&2 #将stdout并进stderr输出。
在 linux 的文件系统中,有个设备文件: /dev/null。将 fd 1跟 fd 2重定向到 /dev/null 去,就可忽略 stdout, stderr 的输出。将 fd 0重定向到 /dev/null,那就是读进空 (nothing)。

(8) 进程替换

bed=exon_probe.hg38.gene.bed
for bam in ~/*.bam
do file=$(basename $bam)
sample=${file%%.*}
echo $sample
export total_reads=$(samtools idxstats $bam | awk -F '\t' '{s+=$3}END{print s}')
echo The number of reads is $total_reads
bedtools multicov -bams $bam -bed   $bed | perl -alne '{$len=$F[2]-$F[1];if($len <1) {print "$.\t$F[4]\t0"}else{$rpkm=(1000000000*$F[4]/($len*$ENV{total_reads}));print "$.\t$F[4]\t$rpkm"}}' > $sample.rpkm.txt
done

注:
全局变量:export
%%.* #每个%表示删除一个点号及其后的字符串(右删除)。

export bed=13edsfd
echo $bed
perl -e 'print $ENV{bed}'
# https://github.com/jmzeng1314/my_WGCNA 

总结

  • 在bash shell中, $()与 `` (反引号)都是用来做命令替换的。
  • $(())是用来作整数运算的。
  • 全局变量:export
  • basename #去除路径等,只剩基本文件名。
  • %%.* #每个%表示删除一个点号及其后的字符串。

参考阅读
1. Linux Shell基础 - Bash变量 - 环境变量 - 位置参数变量 - 预定义变量
2. 菜鸟学Linux - 变量基本规则
3. Shell 十三问
4. shell循环:for、while、until——详解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hucy_Bioinfo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值