bash issue with variables containing a single quote

45 views Asked by At

I'm trying to run a command at the command prompt and if one of the values includes a single quote it doesn't run correctly.

The command I'm using is :

lxc-attach -n test -- bash -c 'echo 'abcd1234' > /home/rocket/test.log'

This will complete without issue and abcd1234 is written to the test.log correctly.

However if I run the command with abcd'1234 then the command doesn't update the log file.

lxc-attach -n test -- bash -c 'echo 'abcd'1234' > /home/rocket/test.log'

I've tried escaping the ' with \ but that hasn't helped.

Could someone advise how to get this to run.

Thanks

UPDATE I'm actually running this from a PHP page and using SSH to update the server. The actual command being run is:

$update = "echo $password | sudo -S lxc-attach -n $server -- bash -c 'echo \"$value\" >> /home/rocket/test.log'";
$ssh->exec( $update );

Where $value may contain a single quote.

3

There are 3 answers

2
Gilles Quénot On

What I would do:

lxc-attach -n test -- bash -c 'echo "abcd'1234" > /home/rocket/test.log'

or:

lxc-attach -n test -- bash<<'EOF'
echo "abcd'1234" > /home/rocket/test.log
EOF
0
Rocket On

I've managed to get this working.

$value = str_replace( "'", "'\''", $value );

$update = "echo $password | sudo -S lxc-attach -n $server -- bash -c 'echo \"$value\" >> /home/rocket/test.log'";

$value is now shown correctly in the log file.

0
amphetamachine On

Since $password is completely arbitrary, you'll want to use escapeshellarg on it to sanitize it.

Since this is a complex command, you'll need to use it multiple times, it's the only way to be sure the inputs are completely sanitized. I've gone ahead and fixed the escaping on $value and $server too:

$bash_command = 'echo ' . escapeshellarg($value) . ' >> /home/rocket/test.log';
$update = 'echo ' . escapeshellarg($password) .
    ' | sudo -S lxc-attach -n ' . escapeshellarg($server) .
    ' -- bash -c ' . escapeshellarg($bash_command);

$ssh->exec( $update );

Cleaner solution using sprintf:

$bash_command = sprintf('echo %s >> /home/rocket/test.log',
    escapeshellarg($value),
);
$update = sprintf('echo %s | sudo -S lxc-attach -n %s -- bash -c %s',
    escapeshellarg($password),
    escapeshellarg($server),
    escapeshellarg($bash_command),
);
$ssh->exec( $update );

Doing this results in the sanitized string,

echo 'abcd'\''1234' | sudo -S lxc-attach -n 'example.com' -- bash -c 'echo '\''hello world'\'' >> /home/rocket/test.log'

And yes, that absolute mess IS how you need to phrase literal single quotes when used alongside single-quoted strings in shell. Hey look, even SO's markdown parser has trouble with it. O__o Luckily you don't need to care about manually doing it if you use escapeshellarg in my code above.

I'm always paranoid about user-generated input ever since the Bobby Tables incident.