好久没写过技术笔记了,再加上最近不想写论文也不太想碰代码,干脆稍微写一点简单的内容;鉴于最近跑程序用到输入输出重定向比较多,就写点这个吧,也备日后再次用到时查询。

输入输出重定向是一个很简单的概念,无非是把本来应该通过命令行界面输入/输出的内容改成通过文件罢了。具体来说可以分成三类:输入重定向,标准输出重定向和标准错误重定向,分别按以下命令即可:

someCommond < someFile
someCommond > stdout # or someCommond 1> stdout
someCommond 2> stderr

要想把标准输出和错误塞一个文件里,直接

someCommond 1> stdout 2>&1

如果想要在文件尾追加而非覆盖,那么把 > 改成 >> 即可。

总之,抽象的说就是,在Linux中, 0 代表标准输入流, 1 代表标准输出流, 2 代表标准错误流, > >> 是重定向, & 类似于取地址。因此,上面那行代码为例,就可以说成是“把1(即标准输出)重定向到 stdout 这个文件,2(标准错误)重定向到标准输出(的位置)”。整个逻辑还是很简单明了的。

那么接下来就记录一下最近遇到的小问题以及如何用输入输出重定向解决的。

问题的背景是,要运行一个叫做 MergerTree 的命令行程序,以分析AHF产生的数据。它通过命令行交互式的获取输入,包括待分析的数据文件总数、数据文件文件名和分析后的输出数据文件文件名。若有N个数据文件,那么就需要输入这个N个数据文件的文件名和N-1个输出数据文件的文件名;而AHF产生的数据有N组,每组一个文件夹;第i个输出数据文件需要放在第i个数据文件所在的文件夹中。因此,最终 MergerTree 运行时的输入类似于:

Please give number of particles files (default=2):      2 # this line is input
2
Please give name of     1. *_particles file:         ./L7H10_CR_16/470/output.z0.239.AHF_particles # this line is input
./L7H10_CR_16/470/output.z0.239.AHF_particles
Please give name of     2. *_particles file:              ./L7H10_CR_16/469/output.z0.241.AHF_particles # this line is input
./L7H10_CR_16/469/output.z0.241.AHF_particles
Please give prefix for     1. output file:                   ./L7H10_CR_16/470/output # this line is input
./L7H10_CR_16/470/output

# MergerTree is running and some logs ...

这里,待分析的数据文件有2个,因此第一次输入 2 ;这两个数据文件分别是 ./L7H10_CR_16/470/output.z0.239.AHF_particles ./L7H10_CR_16/469/output.z0.241.AHF_particles ,输出文件的文件夹与第一个数据文件相同,于是是 ./L7H10_CR_16/470/output

当然,实际过程中待分析的数据文件不是2个,否则我直接这样输入就成了:实际有221个。所幸的是,虽然数据文件本身的命名中有很难格式化生成的部分,但数据文件所在的文件夹则是直接按编号命名;同时程序也只需要后缀为 .AHF_particles 的文件。因此考虑的解决方案为,利用 python 生成标准输入文件,然后将 MergerTree 的输入重定向到这个文件。

最后的 .py 文件为:

import os

def gen_MergerTree_input(snap_list: list):
    snap_list.reverse() # MergerTree needs larger index input first
    file_dir = "./L7H10_CR_16/" # parent dir of every data dir
    input_fns = ""; output_fns = ""
    snap_num = len(snap_list)
    for snapshot in snap_list:
        sub_dir = file_dir + str(snapshot) + "/" # every data dir
        fns = os.listdir(sub_dir)
        for fn in fns:
            if fn.split(".")[-1] == "AHF_particles": # MergerTree only need this file
                input_fn = sub_dir + fn
                output_fn = sub_dir + "output"
                input_fns += (input_fn + "\n") # "\n" to input one file
                if snapshot != snap_list[-1]:
                    output_fns += (output_fn + "\n") # the last index doesn't need output
    stdin = "{}\n{}{}".format(snap_num, input_fns, output_fns) # construct stdin file: first line is total number of input files, and then input filename, and then output file prefix
    with open("./stdin", "w") as f:
        f.write(stdin)
    return

start_snap = 250
end_snap = 471
snap_list = list(range(250, 471)) # directory indexes
gen_MergerTree_input(snap_list)

那么,最后产生的 stdin 文件类似于:

221
./L7H10_CR_16/470/output.z0.239.AHF_particles
./L7H10_CR_16/469/output.z0.241.AHF_particles
./L7H10_CR_16/468/output.z0.244.AHF_particles
...
./L7H10_CR_16/250/output.z1.187.AHF_particles
./L7H10_CR_16/470/output
./L7H10_CR_16/469/output
...
./L7H10_CR_16/251/output

最后,只需要 ./MergerTree < stdin ,这事就这么成了:

user@where$ ./MergerTree < stdin
...
Please give number of particles files (default=2):      221
Please give name of     1. *_particles file:            ./L7H10_CR_16/470/output.z0.239.AHF_particles
Please give name of     2. *_particles file:            ./L7H10_CR_16/469/output.z0.241.AHF_particles
Please give name of     3. *_particles file:            ./L7H10_CR_16/468/output.z0.244.AHF_particles
...
Please give name of   221. *_particles file:            ./L7H10_CR_16/250/output.z1.187.AHF_particles
Please give prefix for     1. output file:                 ./L7H10_CR_16/470/output
Please give prefix for     2. output file:                 ./L7H10_CR_16/469/output
Please give prefix for     3. output file:                 ./L7H10_CR_16/468/output
...
Please give prefix for   220. output file:                 ./L7H10_CR_16/251/output

Startup:
...
Cleaning up ... finished

好,收工!