Как избавиться от синтаксической ошибки, которая возникает с помощью нескольких одинарных кавычек в команде - PullRequest
0 голосов
/ 28 ноября 2018

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

# last logged in time of ubuntu user

user_login = os.popen('ssh -i /Users/abcxyz/keypair ubuntu@1#.###.##.# lastlog -u 'ubuntu' | grep -v Latest | awk '{$1="";$2="";$3="";print $0 }'').read()

print(user_output)

когда я просто запускаю это в своем терминале, он работает нормально и выдает мне вывод:

ssh -i /Users/abcxyz/keypair ubuntu@1#.###.##.# lastlog -u 'ubuntu' | grep -v Latest | awk '{$1="";$2="";$3="";print $0 }'

Вывод: Sat Nov 17 16:32:10 +0000 2018

Ответы [ 2 ]

0 голосов
/ 28 ноября 2018

В идеале , вы должны сконструировать это таким образом, чтобы вообще не подвергать вас этой проблеме - то есть, пусть интерпретатор Python выполняет работу по генерации правильно заключенных в кавычкиstring (а затем снова заключить его в кавычки для безопасной передачи в ssh).

try:
  from shlex import quote # Python 3
except ImportError:
  from pipes import quote # Python 2
import subprocess

# specify your commands the way they're actually seen by the operating system -- with
# lists of strings as argument vectors.
rmt_pipeline = [[ 'lastlog', '-u', 'ubuntu' ],
                [ 'grep', '-v', 'Latest' ],
                [ 'awk', '{$1="";$2="";$3="";print $0 }' ]]

# ...then, let shlex.quote() or pipes.quote() determine how to make those lists be valid
# shell syntax, as expected by the remote copy of sh -c '...' invoked by ssh
rmt_pipeline_str = ' | '.join(' '.join(quote(word) for word in piece)
                              for piece in rmt_pipeline)

# ...finally, generate the argument vector for our local copy of ssh...
ssh_cmd = [ 'ssh', '-i', '/Users/abcxyz/keypair', rmt_pipeline_str ]

# and actually invoke it.
user_output = subprocess.Popen(ssh_cmd, stdout=subprocess.PIPE).stdout

Если вы действительно хотите использовать os.popen() - что не следует, как Pythonдокументация явно предлагает использовать subprocess вместо - вы можете заменить последнюю строку на:

ssh_cmd_str = ' '.join(quote(word) for word in ssh_cmd)
user_output = os.popen(ssh_cmd_str)

В операционных системах семейства UNIX выполнение всех программ происходит через execve() syscall, который передает список строк C.Указав этот список самостоятельно, вы получаете максимально возможный контроль над тем, как происходит выполнение, и предотвращаете атаки с внедрением оболочки (когда пользователь, уполномоченный предоставлять параметр для одной из ваших программ, передает содержимое, интерпретируемое оболочкой как синтаксис, а не какданные, и, следовательно, вместо этого запускает совершенно другую программу или операцию косвенного обращения.

0 голосов
/ 28 ноября 2018

Поскольку в вашей строке есть как одинарные, так и двойные кавычки, я бы все это заключил в тройные кавычки

user_login = os.popen("""ssh -i /Users/abcxyz/keypair ubuntu@1#.###.##.# lastlog -u 'ubuntu' | grep -v Latest | awk '{$1="";$2="";$3="";print $0 }'""").read()

В противном случае, как написано, некоторые из одинарных кавычек внутри вашей строки заканчиваются на всю длинустрока в середине

...