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()