Python 将一个命令输入到一个目录中以逗号分隔的文件名列表中,从文件名中提取一个变量motif作为标签
我有一个包含如下文件的目录:Python 将一个命令输入到一个目录中以逗号分隔的文件名列表中,从文件名中提取一个变量motif作为标签,python,bash,terminal,Python,Bash,Terminal,我有一个包含如下文件的目录: 1_reads.fastq 2_reads.fastq 89_reads.fastq 42_reads.fastq program.py -i 1_reads.fastq,2_reads.fastq,89_reads.fastq,42_reads.fastq program.py -i 1_reads.fastq,2_reads.fastq,89_reads.fastq,42_reads.fastq -t s1,s2,s89,s42 我想将这些文件名的逗号分隔
1_reads.fastq
2_reads.fastq
89_reads.fastq
42_reads.fastq
program.py -i 1_reads.fastq,2_reads.fastq,89_reads.fastq,42_reads.fastq
program.py -i 1_reads.fastq,2_reads.fastq,89_reads.fastq,42_reads.fastq -t s1,s2,s89,s42
我想将这些文件名的逗号分隔列表提供给python程序中的命令,因此python命令的输入如下所示:
1_reads.fastq
2_reads.fastq
89_reads.fastq
42_reads.fastq
program.py -i 1_reads.fastq,2_reads.fastq,89_reads.fastq,42_reads.fastq
program.py -i 1_reads.fastq,2_reads.fastq,89_reads.fastq,42_reads.fastq -t s1,s2,s89,s42
此外,我希望在python命令中使用文件名中的数字作为标记函数,以便输入如下所示:
1_reads.fastq
2_reads.fastq
89_reads.fastq
42_reads.fastq
program.py -i 1_reads.fastq,2_reads.fastq,89_reads.fastq,42_reads.fastq
program.py -i 1_reads.fastq,2_reads.fastq,89_reads.fastq,42_reads.fastq -t s1,s2,s89,s42
重要的是,文件名和标签ID的顺序相同。尝试以下方法:
program.py $(cd DIR && var=$(ls) && echo $var | tr ' ' ',')
它将把$(..)中te命令行返回的字符串传递给program.py
该命令行将:在目录中输入,运行ls,将输出存储在变量中,这将删除换行符并替换为空格,并且不会添加尾随空格。然后将该变量回显为“tr”,这将把空格转换为逗号。首先:这是一个考虑不周的调用约定。不要用它 然而,如果你正在使用其他人编写的软件,那么已经有了这种约定
#!/bin/bash
IFS=, # use comma as separator
files=( [[:digit:]]*_* )
[[ -e $files || -L $files ]] || { echo "ERROR: No files matching glob exist" >&2; exit 1; }
prefixes=( )
for file in "${files[@]}"; do
prefixes+=( "s${file%%_*}" )
done
# "exec" only if this is the last command in the script; remove otherwise
exec program.py -i "${files[*]}" -t "${prefixes[*]}"
工作原理:
导致IFS=,
在每个展开的元素之间放置逗号。因此,展开${array[*]}
和${files[*]}
将创建带有每个数组内容的逗号分隔字符串${prefixes[*]}
删除文件名中第一个${file%%\*}
之后的所有内容,只允许提取数字\
实际上只测试该数组中的第一个元素是否存在(作为符号链接或其他形式);但是,如果要展开以形成数组的glob与任何文件匹配(除非在两行调用之间删除了文件),则始终是这样[[-e$files | |-L$files]]
- 在纯Bash中可以轻松完成。确保从包含文件的目录中运行
#!/bin/bash
shopt -s extglob nullglob
# Create an array of files
f=( +([[:digit:]])_reads.fastq )
# Check that there are some files...
if ((${#f[@]}==0)); then
echo "No files found. Exiting."
exit
fi
# Create an array of labels, directly from the array f:
# Remove trailing _reads.fastq
l=( "${f[@]%_reads.fastq}" )
# And prepend the letter s
l=( "${l[@]/#/s}" )
# Now the arrays f and l are good: check them:
declare -p f l
# To join the arrays, we'll use eval. Safe because the code is single-quoted!
IFS=, eval 'program.py -i "${f[*]}" -t "${l[*]}"'
注意。这里使用
eval
是非常安全的,因为我们传递的是一个常量字符串(实际上,这是一种惯用的方法,可以在不使用子shell或循环的情况下连接数组)。不要修改命令,尤其是单引号
感谢Charles Duffy,他说服我添加有关使用
eval
的健康评论,如果你的名字中有逗号,会发生什么?标准工具不使用“逗号分隔”是有充分理由的。(即使是那些接受换行分隔格式的名称列表的工具也越来越多地允许NUL分隔的流作为一种更健壮的替代方法)。如果我理解你的问题,我想你可以把它改为:“如何转换逗号分隔列表中的文件名列表?(cd“$dir”&&names=(*)&&&{IFS=”,“;echo“${names[*]}”;)
,如果你真的想这样做的话。没有任何理由让ls
这样做。而且,echo$var |……
会将名称中的制表符改为空格,将名称中的glob扩展到其他文件的列表中,等等;你需要引用你的扩展来阻止它们把事情搞砸。即使这样,echo$var
也会以未定义的方式运行请创建一个名为-n
的文件。另外,在cd DIR
之后添加一个&&
;否则,如果cd
失败,此代码将在当前目录中生成一个文件列表。@CharlesDuffy我想在他的情况下,这不会引起关注,因为他的目录中的文件名似乎遵循安全的文件名模式。我曾经见过multiple TB用于计费的访问日志备份被删除,因为有人有一个脚本假设所有文件都将遵循安全模式——然后在该目录中创建文件的工具中的一个缓冲区溢出将随机垃圾转储到文件名中,该文件名碰巧包含一个两边都有空格的*
埃森:即使你认为这无关紧要,也要小心,这样你就不会发现自己在一个充满伤害的世界里,而事实证明确实如此。