Как безопасно называть тип в случайном файле в Python?

Поэтому я пытаюсь вызвать тип команды Windows в каком-то произвольном файле. К сожалению, всякий раз, когда я преобразовываю свой cmd в команду оболочки в не-оболочку, она терпит неудачу. Таким образом, я не могу использовать рекомендуемый метод для обеспечения того, чтобы мой python script не мог быть использован. Вот пример.

import subprocess
cmd = "type" + '"' + "some_file_with_no_spaces_or_other_things_wrong" + '"'
p = subprocess.pOpen(cmd, shell = True)

но при попытке:

#Assume cmd split is done properly. Even when I manually put in the 
#array with properly escaped quotes it does not work
subprocess.pOpen(cmd.split(), shell = False)

Это не удается, и я не знаю, как решить эту проблему. Я хотел бы иметь возможность называть эту команду безопасно, имея оболочку с помощью false, но всякий раз, когда я это делаю, я получаю следующую ошибку.

Traceback (most recent call last):
  File "C:\Users\Skylion\git\LVDOWin\Bin\Osiris.py", line 72, in openFileDialog
    stderr = STDOUT, shell = False, bufsize = 0, universal_newlines=True)
  File "C:\Python34\lib\subprocess.py", line 859, in __init__
    restore_signals, start_new_session)
  File "C:\Python34\lib\subprocess.py", line 1112, in _execute_child
    startupinfo)
FileNotFoundError: [WinError 2] The system cannot find the file specified

Обратите внимание, что даже работает: subprocess.Popen(['type']) Выбросит ошибку. Моя проблема заключается в том, как я дезинфицирую имя файла, чтобы я мог либо запустить имя файла с помощью shell = True, либо правильно обработать shell = False.

Любая помощь в том, как правильно открыть файл таким образом, будет с благодарностью.

Ответы

Ответ 1

type является внутренней командой, поэтому вам нужно запустить cmd.exe, например, неявно через shell=True.

Если вы передадите команду в виде списка в Windows, то subprocess.list2cmdline() вызывается для преобразования списка в строку, чтобы перейти к CreateProcess() Windows API. Его синтаксис отличается от синтаксиса cmd.exe. Для получения дополнительной информации прочитайте ссылки в этом ответе.

Передайте команду оболочки в виде строки и добавьте shell=True:

from subprocess import check_call

check_call(r'type "C:\path\with spaces & special symbols.txt"', shell=True)

Примечание: префикс r'' используется, чтобы избежать экранирования backslahes в литеральной строке.

Если команда работает так же, как из командной строки, она также должна работать и с Python.

Если имя файла указывается в переменной, вы можете избежать его для оболочки cmd с помощью ^:

escaped_filename = filename_with_possible_shell_meta_chars.replace("", "^")[:-1]
check_call('type ' + escaped_filename, shell=True)

Примечание: нет явных кавычек.

Очевидно, вы могли бы эмулировать команду type в чистом Python:

TYPE копирует консольное устройство (или в другое место) если перенаправлено). Не проверяется, что файл является читаемым текстом.

Если вам нужно только прочитать файл; используйте функцию open():

with open(r'C:\path\with spaces & special symbols.txt', 
          encoding=character_encoding) as file:
    text = file.read()

Если вы не укажете явное кодирование, тогда open() использует кодовую страницу ANSI, например 'cp1252' (locale.getpreferredencoding(False)), чтобы декодировать содержимое файла в текст Unicode.

Примечание: здесь необходимо учитывать 4 символьных кодировки:

  • символьная кодировка самого текстового файла. Это может быть любое, например, utf-8
  • Кодовая страница ANSI, используемая приложениями GUI, такими как notepad.exe например, cp1252 или cp1251
  • Кодовая страница OEM, используемая cmd.exe, например, cp437 или cp866. Они могут использоваться для вывода команды type при ее перенаправлении
  • utf-16, используемый Unicode API, например WriteConsoleW(), например, когда используется переключатель cmd /U. Примечание. Консоль Windows отображает UCS-2, т.е. Поддерживаются только символы Unicode BMP, но копия-паста работает даже для астральных символов, таких как 😊 (U + 1F60A).

См. Следите за кодовой страницей.

Чтобы распечатать Unicode в консоли Windows, см. Что такое сделка с Python 3.4, Unicode, разными языками и Windows?