朝花夕拾-4-shell

引言

shell,我们经常会用到,以其强大的功能,会帮助我们解决很多棘手的问题。最近遇到一个问题,要跑很多case,如果串行的执行,需要很久。能不能让他们并行起来,但又不能所有case都并行运行呢?,因为所有case同时运行,机器会挂掉的。


1,方式1

比较直接的一种方式是,维护两个文件队列(*.start和*.stop)分别记录所有case的运行状态,然后根据并发数量来获取和分配资源。

代码如下:

multi.sh:

#!/bin/bash

#Rill create to run cases parallel
#2014-05-22 

#mkdir ./case_status
#declare -i pc_num
readonly pc_num = 3
case_list = "a b c d e f"

function get_start_num()
{
	num = 0
	for var in $case_list
	do
		if [ -e $var.start -a -f $var.start]; then
			num = num + 1
		fi
	done

	return $num
}


function get_case_stop()
{
	case $1 in
	"a")
		echo "get case: $1 not stop"
		rerurn 0
	;;

	"b")
		echo "get case: $1 stop"
		return 1
	;;

	"c")
		echo "get case: $1 not stop"
		rerurn 0
	;;
	
	"d")
		echo "get case: $1 stop"
		rerurn 1
	;;

	"e")
		echo "get case: $1 stop"
		rerurn 1
	;;

	"f")
		echo "get case: $1 stop"
		rerurn 1
	;;
	
	*)
		echo "case $1 not exist"
		exit 1;
	;;
}


for each_d in ${case_list};
do
	if [ get_start_num -lt $pc_num ];then
		if [ ! -e $each_d.start ]; then
			if [ ! -e $each_d.stop ]; then
				touch $each_d.start
				#start one new case
			else
				echo "$each_d already stoped"
				rm $each_d.start
			fi
	
		else
			if [ ! -e $each_d.stop ]; then
				echo "$each_d running......"
				if[ get_case_stop $each_d eq 1];then
					touch $each_d.stop
					rm $each_d.start
				fi
			else
				echo "$each_d error!"
			fi
			
		fi
	fi
done

需要注意的是采用这种方式的话,需要获得每个case的结束状态,这个可以通过case运行结束时的输出log中分析得到。

虽然有awk等强大的工具,但是,分析获得不同case的结束信息仍然是一项艰巨的任务。

有没有其他的方式呢?

有。


2,方式2

仔细分析所有的cases开始,结束的情景,发现和fifo文件的特性很类似,于是就想到用fifo来实现并发控制。

如下:

multi.sh:

#!/bin/bash

#Rill create to run cases parallel
#2014-05-22 

case_list="a b c d e f g h i j k l m n o"

readonly parallel_num=3
readonly fifo_id=9
readonly fifo_name=fd2
readonly log_name=log.log

#create log file
if [ -e ${log_name} -a -f ${log_name} ];then
	rm -f ${log_name}
fi
touch ${log_name}
echo "all cases begin time:$(date +%Y-%m-%d-%H:%M:%S)" >>${log_name}

#create fifo file
if [ -e ${fifo_name} -a -f ${fifo_name} ];then
	rm -f ${fifo_name}
fi
mkfifo ${fifo_name}


#bind fifo to fifo_id
eval "exec ${fifo_id}<>${fifo_name}"

#init fifo
for (( idx=0;idx<${parallel_num};idx=idx+1 ))
do
echo -n -e "1\n" >>${fifo_name}
done

#multi main body
for each_case in ${case_list};
do
	read -u ${fifo_id}
	{
		echo "${each_case} start:$(date +%Y-%m-%d-%H:%M:%S)" >>${log_name}
		sleep 1  #case running
		echo "${each_case} stoped:$(date +%Y-%m-%d-%H:%M:%S)" >>${log_name}
		echo -ne "1\n" >>${fifo_name}
	} &
done

#wait all the cases stoped
wait

echo "all cases finish time:$(date +%Y-%m-%d-%H:%M:%S)" >>${log_name}

#remove the fifo
rm -f ${fifo_name}


从中可以发现,我们不需要再为获得case的结束状态而烦恼了。

下面是运行结果,一共15个case,每个case运行1秒,并发数量设置为3,所有case运行完需要6.4秒左右。





3,shell参数传递

平时我们在使用shell脚本时,往往要向脚本中指定参数,这些参数可以直接写在命令行的后面,但是这样做对参数顺序要求很强,使用起来比较困难。

这时我们可以通过在参数前面增加标示来实现。


#!/bin/bash

#
# shell test
# Rill
# 2014-09-28

opr1=x
opr2=x
opr3=x

while [ -n "$(echo $1 | grep '-')" ];do
    case $1 in
	-h | --help)
	    echo "./test.sh -opr1 a -opr2 b -opr3 c"
	    exit 0
	    ;;
	-opr1)
	    opr1=$2
	    shift
	    ;;
	
	-opr2)
	    opr2=$2
	    shift
	    ;;
	
	-opr3)
	    opr3=$2
	    shift
	    ;;

    esac
    
    shift

done


echo "opr1=${opr1}  opr2=${opr2}  opr3=${opr3}"


验证结果:




4,小结

shell很久都不用了,本小结就当“朝花夕拾”吧。


### NCBI 批量下载基因序列方法或工具 为了从NCBI批量下载基因序列,可以通过多种方式实现。以下是几种常用的方法和技术: #### 使用 Batch Entrez 工具 NCBI 提供了一个名为 **Batch Entrez** 的在线工具[^1],允许用户通过上传基因ID列表或其他标识符来检索和下载大量基因数据。然而需要注意的是,Gene 数据库的检索结果通常不会直接返回 FASTA 序列文件,而是需要进一步处理才能获取到所需的 `gene.fna` 文件。 如果目标是从 Gene 数据库中提取 FASTA 格式的基因序列,则可能需要额外的操作步骤,比如手动点击 Download Datasets 键以获得压缩包形式的数据集。不过该工具有一定的限制条件,例如单次操作的最大记录数约为 300 条[^2],这可能会对大规模数据分析造成不便。 #### 编程自动化解决方案 (R 和 Python) ##### R语言脚本方案 利用 R 脚本编写程序能够高效完成针对多个基因 ID 进行自动化的网络请求任务,并从中解析出对应的注释信息以及序列等内容[^3]。具体流程如下所示: ```r library(xml2) library(httr) get_gene_info <- function(genes){ base_url <- "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi" params <- list(db="gene", term=paste(genes,collapse=",")) res_search <- GET(base_url,params=params) doc <- read_xml(content(res_search,type="text"),as_html=FALSE) ids <- xml_text(xml_find_all(doc,"//IdList/Id")) paste(ids,collapse="\n") } download_genes_fasta <- function(ids){ fetch_base <- "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi" fasta_data <- character() for(id in strsplit(ids,"\n")[[1]]){ param_fetch <- list(db="nuccore", id=id, rettype="fasta", retmode="text") temp_res <- GET(fetch_base,param_fetch) if(status_code(temp_res)==200){ fasta_data <- c(fasta_data,content(temp_res,type="text")) } } cat(paste(fasta_data,sep="",collapse="\n")) } ``` ##### Python脚本方案 另一种可行的选择是采用 Python 编写类似的逻辑代码片段来进行大批量的数据抓取工作[^4][^5]。下面给出了一段示范性的例子用于说明如何构建 URL 请求字符串从而访问指定资源位置进而取得相应的FASTA格式化后的核酸链表征数值。 ```python import requests def get_fasta_sequence(gene_ids): url_template = ( "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/" "efetch.fcgi?db=nucleotide&id={}&rettype=fasta&retmode=text" ) sequences = [] for gene_id in gene_ids.split(","): response = requests.get(url_template.format(gene_id.strip())) if response.status_code == 200: sequences.append(response.text) return "\n".join(sequences) if __name__ == "__main__": genes_to_query = input("Enter comma-separated list of gene IDs:") result = get_fasta_sequence(genes_to_query) with open("output_sequences.fasta","w") as f_out: f_out.write(result) ``` 以上两种编程语言均提供了灵活且强大的功能支持去满足科研人员日常工作中关于海量生物分子水平上的探索需求。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值