Sh: 1: Синтаксическая ошибка: Непрерванная кавычки\n

Я делаю онлайн-судью в django frame work Я пытаюсь запустить программу на c++ внутри контейнера docker через подпроцесс. Вот строка, где я получаю ошибку

 x=subprocess.run('docker exec oj-cpp sh -c \'echo "{}" | ./a.out \''.format(problem_testcase.input),capture_output=True,shell=True)

здесь oj-cpp - имя моего контейнера docker, а problem_testcase.input - вход для файла c++

С++ код:

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int t;
    while (t--)
    {
        int a, b;
        cin >> a >> b;
        cout << a + b << endl;
    }
    return 0;
}

problem_testcase.input:

2
4
5
3
5

ошибка:

CompletedProcess(args='docker exec oj-cpp sh -c \'echo "2\n4\n5\n3\n5" | ./output\'', returncode=2, stdout=b'', stderr=b'2: 1: Syntax error: Unterminated quoted string\n')

Я не понимаю, что не так в моем коде

subprocess.call(shell=True) имеет некоторые существенные проблемы с безопасностью, и я бы избегал его при любой возможности. Он открывает ваше приложение для атаки инъекции оболочки. Вы фактически видите это в своем коде: если строка в problem_testcase.input содержит какие-либо символы, значимые для оболочки, оболочка интерпретирует их, что может заставить ее делать неожиданные вещи.

В вашем вводе Python расширяет \n новые строки и затем передает их запускаемой оболочке хоста. Таким образом, выполняемая команда оболочки выглядит следующим образом

docker exec oj-cpp sh -c 'echo "2
4
5
3
5" | ./a.out '

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


Здесь важно знать, что docker exec будет передавать свой собственный stdin в программу, которую он запускает. Поэтому вам не нужен синтаксис echo input | program; поскольку он вам не нужен, вам не нужен вызов sh -c; и поскольку вы выполняете только фиксированную команду без замен, вам не нужен shell=True.

x = subprocess.run(['docker', 'exec', 'oj-cpp', './a.out'],
                   input=problem_testcase.input,
                   capture_output=True)

Я могу внести еще два изменения в эту программу.

Docker SDK for Python обеспечивает более прямой доступ к функциональности Docker, без использования subprocess. Он не требует бинарных файлов docker, хотя для этого все равно необходимо, чтобы демон Docker был запущен и чтобы у вас было разрешение на доступ к нему.

Я бы также избегал сценариев docker exec. Если рассматривать контейнер как обертку вокруг одного процесса, docker exec запускает второй процесс внутри этого процесса, что немного странно. Если вы docker run создаете новый (временный) контейнер, он запускается в известном состоянии, и снижается риск того, что различные вызовы программ будут мешать друг другу.

import docker
client = docker.from_env()

# Start the container (`docker run -d -i some_image`)
container = client.containers.run(some_image, detach=True, stdin_open=True)

# Send the input string into the container
socket = container.attach_socket()
socket.send(problem_testcase.input.encode('utf-8'))
socket.close()

# Let the program run, collect its output, clean up
container.wait()
output = container.logs()
container.remove()
Вернуться на верх