Skip to content

Commit 2e61443

Browse files
author
Dan
committed
Fixed shell cmd quoting - resolves #39. Added unit tests for several more special characters in cmd and running multiple shell commands in one go
1 parent f60b077 commit 2e61443

File tree

2 files changed

+43
-9
lines changed

2 files changed

+43
-9
lines changed

pssh/ssh_client.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -218,17 +218,18 @@ def exec_command(self, command, sudo=False, user=None,
218218
stdout, stderr = self._read_output_buffer(_stdout,), \
219219
self._read_output_buffer(_stderr,
220220
prefix='\t[err]')
221-
221+
for _char in ['\\', '"', '$', '`']:
222+
command = command.replace(_char, '\%s' % (_char,))
222223
shell = '$SHELL -c' if not shell else shell
223224
_command = ''
224225
if sudo and not user:
225226
_command = 'sudo -S '
226227
elif user:
227228
_command = 'sudo -u %s -S ' % (user,)
228229
if use_shell:
229-
_command += '%s \'%s\'' % (shell, command,)
230+
_command += '%s "%s"' % (shell, command,)
230231
else:
231-
_command += '\'%s\'' % (command,)
232+
_command += '"%s"' % (command,)
232233
logger.debug("Running parsed command %s on %s", _command, self.host)
233234
channel.exec_command(_command, **kwargs)
234235
logger.debug("Command started")

tests/test_pssh_client.py

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,7 @@ def test_identical_host_output(self):
513513
msg="Host list contains %s identical hosts, only got output for %s" % (
514514
len(hosts), len(output.keys())))
515515
del _socket1, _socket2
516-
516+
517517
def test_connection_error_exception(self):
518518
"""Test that we get connection error exception in output with correct arguments"""
519519
self.server.kill()
@@ -541,7 +541,7 @@ def test_connection_error_exception(self):
541541
else:
542542
raise Exception("Expected ConnectionErrorException")
543543
del _socket
544-
544+
545545
def test_authentication_exception(self):
546546
"""Test that we get authentication exception in output with correct arguments"""
547547
self.server.kill()
@@ -601,16 +601,49 @@ def test_ssh_exception(self):
601601
raise Exception("Expected SSHException")
602602
server.kill()
603603
del _socket
604-
604+
605605
def test_multiple_single_quotes_in_cmd(self):
606+
"""Test that we can run a command with multiple single quotes"""
606607
output = self.client.run_command("echo 'me' 'and me'")
607-
self.client.join(output)
608608
stdout = list(output[self.host]['stdout'])
609609
expected = 'me and me'
610+
self.assertTrue(len(stdout)==1,
611+
msg="Got incorrect number of lines in output - %s" % (stdout,))
610612
self.assertTrue(output[self.host]['exit_code'] == 0,
611613
msg="Error executing cmd with multiple single quotes - %s" % (
612614
stdout,))
613-
self.assertEqual([expected], stdout,
615+
self.assertEqual(expected, stdout[0],
616+
msg="Got unexpected output. Expected %s, got %s" % (
617+
expected, stdout[0],))
618+
619+
def test_backtics_in_cmd(self):
620+
"""Test running command with backtics in it"""
621+
output = self.client.run_command("out=`ls` && echo $out")
622+
self.client.join(output)
623+
self.assertTrue(output[self.host]['exit_code'] == 0,
624+
msg="Error executing cmd with backtics - error code %s" % (
625+
output[self.host]['exit_code'],))
626+
627+
def test_multiple_shell_commands(self):
628+
"""Test running multiple shell commands in one go"""
629+
output = self.client.run_command("echo me; echo and; echo me")
630+
stdout = list(output[self.host]['stdout'])
631+
expected = ["me", "and", "me"]
632+
self.assertTrue(output[self.host]['exit_code'] == 0,
633+
msg="Error executing multiple shell cmds - error code %s" % (
634+
output[self.host]['exit_code'],))
635+
self.assertEqual(expected, stdout,
636+
msg="Got unexpected output. Expected %s, got %s" % (
637+
expected, stdout,))
638+
639+
def test_escaped_quotes(self):
640+
"""Test escaped quotes in shell variable are handled correctly"""
641+
output = self.client.run_command('t="--flags=\\"this\\""; echo $t')
642+
stdout = list(output[self.host]['stdout'])
643+
expected = ['--flags="this"']
644+
self.assertTrue(output[self.host]['exit_code'] == 0,
645+
msg="Error executing multiple shell cmds - error code %s" % (
646+
output[self.host]['exit_code'],))
647+
self.assertEqual(expected, stdout,
614648
msg="Got unexpected output. Expected %s, got %s" % (
615649
expected, stdout,))
616-

0 commit comments

Comments
 (0)