我需要在一个目录中的数千个文件上运行一个命令。但是,我使用的程序需要一个参数文件,在该文件上可以指示输入和输出的名称。命令如下:
./program parameters_file.txt
这些是我需要在parameters_file.txt上编辑的行,即第1-3行。其余行(未显示(保持不变:
input_file = asd123.OK
input_file2 = asd123.TXT
outfile = asd123.RESULTS_OUT
如图所示,所有文件都有匹配的名称,并且只有扩展名发生了更改。
我需要循环这个,以便每次循环重新启动时都覆盖input_file、input_file2和outfile。类似于:用第一个文件名编辑parameters_file.txt,在第一个文件上运行命令,用第二个文件名修改parameters_file.txt,在第二个档案上运行命令等。
思考:
for f in *.OK;
do
input_file = $f
input_file2 = $f.TXT
outfile = $f.RESULTS_OUT
但我不知道如何将其包含在命令中,也无法在parameters_file.txt中写入循环,因为这会使程序崩溃。可能是回显parameters_file.txt还是用sed覆盖?
谢谢。
如果你有数千个文件要处理,每个文件需要一个小时,你可以考虑使用GNU并行并行完成4、8或16个文件,并让所有的CPU核心都很忙,为此你花了英特尔很多钱。。。否则你会在那里呆上几个星期。此外,如果您的网络中有多台计算机GNU并行也可以在它们之间分配作业和数据,以加快速度。
因此,假设需要处理的文件都以*.OK
结束,一个基本的例子是:
parallel -k echo {#} {.} ::: ads123.OK qwe987.OK tyu456.OK
将输出以下内容:
1 ads123
2 qwe987
3 tyu456
所以希望您能看到{#}
只是顺序增加的作业编号,而{.}
是删除了扩展名的文件名。
好吧,现在你想在开始工作之前处理一下你的参数文件,所以你最好为每个预处理的工作写一个bash
函数,就像这样。我将调用函数doit()
:
doit(){
jobnum=$1
name=$2
paramfile="parameters.$jobnum"
echo Processing file: $name with parameters in file: $paramfile
}
# Make our function known to jobs started by GNU Parallel
export -f doit
# Now run the jobs
parallel -k doit {#} {.} ::: *.OK
现在我们所需要做的就是更改doit()
来准备您的参数,这样我们就可以做到:
doit(){
jobnum=$1
name=$2
paramfile="parameters.$jobnum"
echo Processing file: $name with parameters in file: $paramfile
# Following code supplied by @poshi
echo "input_file = $name" > "$paramfile
echo "input_file2 = $name.TXT" >> "$paramfile"
echo "outfile = $name.RESULTS_OUT" >> "$paramfile"
# Add/copy/incorporate the rest of the parameters as you wish
echo program "$paramfile"
}
在进程替换中使用printf,不要麻烦替换parameters_file.txt
中的字符串。
for f in *.OK; do
prog <(
printf 'input_file = %sninput_file2 = %snoutfile = %sn' "${f%OK}"{OK,TXT,RESULTS_OUT}
tail -n +4 parameters_file.txt
)
done
执行创建输入参数文件和的循环,运行程序:
for f in *.OK;
do
echo "input_file = $f" > parameters
"input_file2 = $f.TXT" >> parameters
"outfile = $f.RESULTS_OUT" >> parameters
# Add/copy/incorporate the rest of the parameters as you wish
./program parameters
done
我想这样的东西会达到你想要的:
#!/bin/bash
for file in *.OK; do
sed -i
-e "s/input_file =.*/input_file = ${file}/"
-e "s/input_file2.*/input_file2 = ${file%.OK}.TXT/"
-e "s/outfile.*/outfile = ${file%.OK}.RESULTS_OUT/"
parameters_file.txt
./program parameters_file.txt
done