more <оператор в вызове подпроцесса Python
У меня есть три файла CSV: 1.csv, 2.csv, 3.csv, как эти:
➜ ~ cat 1.csv
1,1,1,1,1,1
➜ ~ cat 2.csv
2,2,2,2,2,2
➜ ~ cat 3.csv
3,3,3,3,3,3
Если я сделаю:
➜ ~ cat < 1.csv < 2.csv < 3.csv > 4.csv
Я получаю:
➜ ~ cat 4.csv
1,1,1,1,1,1
2,2,2,2,2,2
3,3,3,3,3,3
как я хочу.
Теперь я хочу сделать это в Python subprocess.call
import subprocess as sp
sp.call('cat < 1.csv < 2.csv < 3.csv > 4.csv', shell=True)
но результат таков:
➜ ~ cat 4.csv
3,3,3,3,3,3
Таким образом, он не создает файл 4.csv:
sp.call(['cat', '<', '1.csv', '<', '2.csv', '<', '3.csv', '>', '4.csv'], stdout=sp.PIPE,stderr=sp.PIPE
Или же
mylist = ['cat', '<', '1.csv', '<', '2.csv', '<', '3.csv', '>', '4.csv']
sp.call(mylist, stdout=sp.PIPE,stderr=sp.PIPE)
4 ответа
Обе эти работы:
sp.call('cat 1.csv 2.csv 3.csv > 4.csv', shell=True)
а также
sp.call('cat < 1.csv > 4.csv', shell=True)
sp.call('cat < 2.csv >> 4.csv', shell=True)
sp.call('cat < 3.csv >> 4.csv', shell=True)
Не уверен, какова ваша настоящая цель. Если вы просто хотите объединить некоторые файлы, тогда лучше сделать это напрямую в python. Если вы хотите добавить в цепочку некоторые выходные данные программы, я бы сделал это, используя второй метод (по одному на строку).
Это может быть легко достигнуто с помощью только Python:
import fileinput
with open("4.csv", "a") as out:
for f in fileinput.input(["1.csv","2.csv","3.csv"]):
out.write(f)
Используя подпроцесс, вы можете перенаправить:
from subprocess import check_call
with open("4.csv", "a") as out:
check_call(["cat", "1.csv", "2.csv", "3.csv"],stdout=out)
Я бы порекомендовал использовать первый пример.
Если вы перенаправляете несколько раз, все перенаправления выполняются, но вступает в силу только последнее перенаправление (при условии, что ни одно из более ранних перенаправлений не привело к ошибке).
$ cat < 1.csv < 2.csv < 3.csv > 4.csv
Вышеуказанное эквивалентно:
$ cat < 3.csv > 4.csv
если не существует ни одного из 1.csv, 2.csv или 3.csv, в этом случае ожидается, что эта команда не будет выполнена.
Попробуй это:
import subprocess as sp
sp.call('cat 1.csv 2.csv 3.csv > 4.csv', shell=True)
Если fileinput
подход слишком медленный, вы можете попытаться скопировать, используя более крупные куски:
#!/usr/bin/env python
from shutil import copyfileobj
with open('4.csv', 'wb') as output_file:
for filename in ['1.csv', '2.csv', '3.csv']:
with open(filename, 'rb') as file:
copyfileobj(file, output_file)
copyfileobj()
принимает length
параметр, с которым вы можете поэкспериментировать, чтобы выяснить, как он влияет на производительность по времени в вашем случае.
Если этого недостаточно, вы можете попробовать os.sendfile()
:
#!/usr/bin/env python3
import os
with open('4.csv', 'wb') as output_file:
for filename in ['1.csv', '2.csv', '3.csv']:
with open(filename, 'rb') as file:
while os.sendfile(output_file.fileno(), file.fileno(), None, 1 << 30) != 0:
pass