【发布时间】:2021-03-31 15:12:00
【问题描述】:
目标:在特定条件下连接多个 CSV 文件。
- 条件:Windows 10 机器 + 任何 shell 命令(例如,
awk)+ Python - 免责声明:我知道有很多方法可以做到这一点,包括:使用 pandas 数据帧连接;或者使用python的
shutil;或者在 shell 上直接使用系统命令(例如,awk)而不使用 python。但同样,我想要一个完全符合上述条件的答案。
这是我当前正在尝试运行的一个 shell 命令示例(如果我直接在 shell 上运行,它就可以工作)
$ awk "(NR == 1) || (FNR > 1)" "..\\results\\raw*.csv" > "..\\results\\consolidated.csv"
这就是我通过 python 的subprocess 运行它的方式:
src_files = os.path.join('..', 'results', 'raw*.csv')
dest_file = os.path.join('..', 'results', 'consolidated.csv')
result = subprocess.run('awk "(NR == 1) || (FNR > 1)" "{}" > "{}"'.format(src_files, dest_file),
shell=True,
capture_output=True)
但是,我不断收到以下错误:
print(result.stderr)
b"awk: fatal: cannot open file `..\\results\\raw*.csv' for reading (No such file or directory)\n"
我应该指出,如果我在 Unix 机器上运行这个 python 代码,它就可以工作(如果格式 {} 周围的引号被删除)。 python 代码不能在 Windows 机器上运行。
因此,我相信这可能与正确转义命令字符串有关,因为当我指定某些文件的名称时,此命令有效。尽管如此,我还是无法找到转义 * 符号并完成所有这些工作的正确方法。
PS:为工作示例生成数据
for i in range(1, 4):
pd.DataFrame([[i*1, i*2, i*3]], columns=['a', 'b', 'c']).to_csv(os.path.join('results', 'raw-{}.csv'.format(i)), index=False, sep=';')
PS2:使用的文件夹结构
|-- script_folder/
| |-- consolidation_script.py
|-- results/
| |-- raw-1.csv
| |-- raw-2.csv
| |-- raw-3.csv
【问题讨论】:
-
尝试使用
shlex模块来引用参数。 -
嗨@martineau,刚刚尝试了
shlex.quote(),但它仍然没有工作,同样的错误。shlex.join()看起来很有希望,但它只在 python 3.9 中可用,我仅限于 python 3.7。 -
我提出了一个愚蠢的问题,但你为什么需要 awk 来做到这一点?命令“type ..\results\raw*.csv > ..\results\consolidated.csv”不符合您的要求?
-
您尝试运行的命令是
'awk "(NR == 1) || (FNR > 1)" "..\\results\\raw*.csv" > "..\\results\\consolidated.csv"',这对于subprocess.run()来说太复杂了——例如,重定向输出是通过stdout=None关键字参数完成的。我同意@Ian 的观点,这可能最好完全使用 Python 完成,而不是使用像awk这样的外部程序。 -
@IanMcGowan 我不一定需要
awk,它可以是任何shell命令。例如,有些人喜欢使用sed。只是当我想通过shell命令合并.csv文件并保留header时,我最习惯使用awk。