Iokanaan Iokan
Iokanaan Iokan

Reputation: 775

Escaping special characters with sh -c

When I run the following command from shell, it works fine:

# ./testdollar.py 1 2 '"source"="Zabbix"|| "name"="testlog trigger"|| "trigger_name"="*UNKNOWN*"|| "trigger_group"="Zabbix servers"|| "trigger_description"=""|| "id"="291058"|| "item_name"="Testlog"|| "item_value"="HFD3D$01"|| "item_lastvalue"="HFD3D$01"|| "reference_url"="http://test"|| "status_open"="1"|| "hostname"="Zabbix server"||
"ip"="10.10.10.1"|| "value"="1"|| "event_id"="62510700"|| "severity"="Not classified"||
"datetime_item_cst"="1969.12.31 18:00:00"|| "datetime_cst"="2016.10.07 03:59:08"|| "sourceid"="62510700"'

But I need to run it as:

sh -c "the whole command with arguments"

I've tried this:

sh -c /data/zabbix/share/zabbix/alertscripts/testdollar.py 1 2 '"source"="Zabbix"|| "name"="testlog trigger"|| "trigger_name"="*UNKNOWN*"|| "trigger_group"="Zabbix servers"|| "trigger_description"=""|| "id"="291058"|| "item_name"="Testlog"|| "item_value"="HFD3D$01"|| "item_lastvalue"="HFD3D$01"|| "reference_url"="http://test"|| "status_open"="1"|| "hostname"="Zabbix server"||
"ip"="10.10.10.1"|| "value"="1"|| "event_id"="62510700"|| "severity"="Not classified"||
"datetime_item_cst"="1969.12.31 18:00:00"|| "datetime_cst"="2016.10.07 03:59:08"|| "sourceid"="62510700"'

Gives the following error, which indicates that it could not read the third argument that includes a lot of quotes:

Traceback (most recent call last):
  File "/data/zabbix/share/zabbix/alertscripts/testdollar.py", line 3, in <module>
    data=sys.argv[3]
IndexError: list index out of range

Tried this:

sh -c '/data/zabbix/share/zabbix/alertscripts/testdollar.py 1 2 "source"="Zabbix"|| "name"="testlog trigger"|| "trigger_name"="*UNKNOWN*"|| "trigger_group"="Zabbix servers"|| "trigger_description"=""|| "id"="291058"|| "item_name"="Testlog"|| "item_value"="HFD3D$01"|| "item_lastvalue"="HFD3D$01"|| "reference_url"="http://test"|| "status_open"="1"|| "hostname"="Zabbix server"||
"ip"="10.10.10.1"|| "value"="1"|| "event_id"="62510700"|| "severity"="Not classified"||
"datetime_item_cst"="1969.12.31 18:00:00"|| "datetime_cst"="2016.10.07 03:59:08"|| "sourceid"="62510700"'

Which run OK but when I check the outcome of the command, I can see that it stopped reading the third argument just after "source"="Zabbix"|| part. Same thing happens if I wrap the whole thing with double quotes instead of single quotes.

Tried with other combinations of single and double quotes but could not figure it out. Do I need to escape special characters in the command argument? If so, how?

EDIT:

Easier way to test:

sh -c 'echo '"A=x"||"B=y"||"C=z"''
A=x

Upvotes: 0

Views: 389

Answers (1)

Tom Fenech
Tom Fenech

Reputation: 74615

You should use double quotes around the whole command and then escape double quotes within the command string:

sh -c "echo '\"A=x\"||\"B=y\"||\"C=z\"'"

Remember that parameters will be expanded within double quotes, so if you have any $ in your string, then you will need to escape them \$.

The alternative isn't particularly appealing:

sh -c 'echo '"'"'"A=x"||"B=y"||"C=z"'"'"''

To use a single quote ' within a single-quoted string, '"'"' closes the original string, inserts a double-quoted single quote, then reopens a single-quoted string.

If you're targeting Bash specifically, then you can also use a "C-style"/ANSI string:

sh -c $'echo \'"A=x"||"B=y"||"C=z"\''

Within $' ', a single quote can be inserted using \'.

Upvotes: 1

Related Questions