Модуль подпроцесса Python, возвращающий разные результаты из оболочки Unix - PullRequest
4 голосов
/ 02 июля 2010

Я пытаюсь получить список файлов CSV в каталоге с python. Это действительно просто в Unix:

ls -l *.csv

И, как и ожидалось, я получаю список файлов, заканчивающихся на .csv, в моем каталоге. Однако, когда я пытаюсь использовать эквивалент Python с помощью модуля Subprocess:

>>> import subprocess as sp
>>> sp.Popen(["ls", "-l", "*.csv"], stdout = sp.PIPE)
<subprocess.Popen object at 0xb780e90c>
>>> ls: cannot access *.csv: No such file or directory

Может кто-нибудь объяснить, что происходит?

Редактировать : Добавление shell = True устраняет ошибку, но вместо получения списка только CSV-файлов я получаю список всех файлов в каталоге.

Ответы [ 4 ]

4 голосов
/ 02 июля 2010

Если вы хотите, чтобы он вел себя как в оболочке, вам нужно передать shell=True (ваш пробег может варьироваться в зависимости от вашей системы и оболочки). В вашем случае проблема в том, что когда вы делаете ls -l *.csv, оболочка оценивает, что означает *, а не ls. (ls просто форматирует ваши результаты, но оболочка проделала тяжелую работу, чтобы определить, какие файлы соответствуют *.csv). Подпроцесс заставляет ls обрабатывать *.csv буквально и искать файл с таким конкретным именем, которого, конечно, нет (поскольку это довольно сложное имя для создания файла).

Что вы действительно должны делать, так это использовать os.listdir и фильтровать имена самостоятельно.

4 голосов
/ 02 июля 2010

Почему бы не использовать glob вместо этого?Это будет быстрее, чем «обстрел»!

import glob
glob.glob('*.csv')

Это дает вам только имена, а не всю дополнительную информацию ls -l, хотя вы можете получить дополнительную информацию с помощью os.stat вызовов файлов

Если вы действительно должны использовать ls -l, я думаю, вы хотите передать его как строку для оболочки, чтобы выполнить необходимое расширение звезды:

proc = sp.Popen('ls -l *.csv', shell=True, stdout=sp.PIPE)
1 голос
/ 02 июля 2010
p=subprocess.Popen(["ls", "-l", "*.out"], stdout = subprocess.PIPE, shell=True)

вызывает

/bin/sh -c ls -l *.out

будет исполнено.

Если вы попробуете эту команду в каталоге, вы увидите - в типичной манере мистификации - все файлы перечислены. И флаг -l также игнорируется. Это ключ.

Видите ли, флаг -c поднимает только ls. Остальные аргументы съедаются /bin/sh, а не ls.

Чтобы эта команда работала прямо на терминале, вам нужно набрать

/bin/sh -c "ls -l *.out"

Теперь / bin / sh видит полную команду "ls -l * .out" в качестве аргумента для флага -c.

Таким образом, для правильной работы с помощью subprocess.Popen лучше всего просто передать команду в виде одной строки

p=subprocess.Popen("ls -l *.out", stdout = subprocess.PIPE, shell=True)
output,error=p.communicate()
print(output)
1 голос
/ 02 июля 2010

Когда вы вводите ls -l *.csv в оболочке, сама оболочка раскрывает *.csv в список всех имен файлов, которым она соответствует.Таким образом, аргументы ls на самом деле будут похожи на ls -l spam.txt eggs.txt ham.py

Команда ls сама не понимает подстановочные знаки.Поэтому, когда вы передаете ему аргумент *.csv, он пытается обработать его как имя файла, и файла с таким именем не существует.Как говорит Ник, вы можете использовать параметр shell=True, чтобы Python вызывал оболочку для запуска подпроцесса, и оболочка будет расширять символы подстановки для вас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...