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
Другие вопросы по тегам