我有一个简单的代码,可以遍历文件并进行一些简单的演算。以下代码摘录了最大的代码:不要在此代码中要求任何实用程序,这只是问题的最小示例。
#!/bin/bash
#SBATCH --job-name=test
#SBATCH --output=test_%j.out
#SBATCH --error=test_%j.err
#SBATCH --workdir=.
#SBATCH --time=0:5:0
#SBATCH --partition=main
#SBATCH --qos=lowprio
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=4
#SBATCH --requeue
for SM in MB BL
do
while read -r id
do
srun --job-name "Test-${id}" --nodes 1 --ntasks 1 --cpus-per-task 1 ls "$id" 1>&2
echo "${id}"
done < <(grep "$SM" internal.txt | awk '{print $1 "_" $2 "_" $3 ".txt"}') > "test_${SM}.dat"
done
此代码的合理性是:在名为internal.txt
的文件中,我需要将数据列表分为两组,分别为 MB 和 BL 。我使用grep
搜索每个组,我使用awk
组成文件的基本名称,并将其作为while
馈送到id
循环中。在该循环中,我使用srun
来启动命令(在此示例中为ls
),结果,我只输出了$id
。
internal.txt
文件包含:
file 1 BL
file 1 MB
file 2 BL
file 2 MB
file 3 MB
因此,预期的输出是两个文件test_BL.dat
:
file_1_BL.txt
file_2_BL.txt
和test_MB.dat
:
file_1_MB.txt
file_2_MB.txt
file_3_MB.txt
但是现实是我得到了这两个文件……第一行写着test_BL.dat
:
file_1_BL.txt
和test_MB.dat
:
file_1_MB.txt
我已经知道问题所在srun
,因为如果我摆脱了srun
而只留下ls
,它将按预期工作:
#!/bin/bash
#SBATCH --job-name=test
#SBATCH --output=test_%j.out
#SBATCH --error=test_%j.err
#SBATCH --workdir=.
#SBATCH --time=0:5:0
#SBATCH --partition=main
#SBATCH --qos=lowprio
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=4
#SBATCH --requeue
for SM in MB BL
do
while read -r id
do
ls "$id" 1>&2
echo "${id}"
done < <(grep "$SM" internal.txt | awk '{print $1 "_" $2 "_" $3 ".txt"}') > "test_${SM}.dat"
done
最后一个代码运行良好,但是现在我缺少了srun
。对这里发生的事情有任何想法吗?
注意:列出的文件存在。
答案 0 :(得分:2)
感谢@Inian,问题已解决!
诀窍在于,srun
在默认情况下会读取其标准输入,以将其广播到正在启动的其他子进程。它不等待子进程开始从输入中读取,它只是读取其输入并将其保存在缓冲区中,直到有人读取或进程完成(然后丢弃数据)为止。
要解决当前的问题,我们只需要关闭srun的标准输入即可。最简单的方法是通过将--input
参数设置为none
:
srun --input none --job-name "Test-${id}" --nodes 1 --ntasks 1 --cpus-per-task 1 ls "$id" 1>&2
通过使用bash
工具(即添加<&-
)或将/dev/null
重定向到标准输入(< /dev/null
)来关闭标准输入也可以(测试)。 / p>