Create backslash string for sed use
I am creating a command line in python to be executed on a node using pexpect. The sed command I want to run on the host looks like this:
sed -i 's/\(panic=30\)/\1 my_cool_option/g' /boot/bootrc
How do I create a variable in python that keeps the backslash as it is? I originally tried
bootrc = '/boot/bootrc'
param = 'ignorefs'
cmd = "sed -i 's/\(panic=30\)/\\1 {}/g' {}".format(param, bootrc)
self.runExpectCmd(cmd)
When I checked this code in the python shell, it looked quite normal:
>>> bootrc = '/boot/bootrc'
>>> param = 'ignorefs'
>>> cmd = "sed -i 's/\(panic=30\)/\\1 {}/g' {}".format(param, bootrc)
>>> print cmd
sed -i 's/\(panic=30\)/\1 ignorefs/g' /boot/bootrc
However, when I stepped through pdb to understand why the code failed, the cmd was set to
(Pdb) p cmd
"sed -i 's/\\(panic=30\\)/\\1 ignorefs/g' /boot/bootrc"
I don't understand how to create the correct line to execute the sed command.
thank
source to share
This confused me on the first reading of your question, but look at the string literals page
As you probably know, python uses the backslash character \
as the escape character. So, to include a newline in a string literal, type
s = 'hello\nworld'
If we want the actual backslash we use the double backslash
s = '\\'
If the character following the backslash does not match the escape sequence, the backslash is stored as
s = '\ ' # space doesn't match any escape sequence, so you get to keep the backslash
This is what happens to yours \(
- in the end you get<backslash><open parnes>
However, it \1
matches an escape sequence - it is a literal for the octal representation of a character. So instead <backslash>1
you got <0x01>
.
When used p cmd
in pdb, it prints a repr
string, which is used to use a backslash for non-printable characters. This is different from using it print cmd
in the python shell.
python shell:
>>> print '\\'
\
pdb:
(Pdb) p '\\'
'\\'
Pdb shows you that you have a backslash. Similarly
>>> print repr('\\')
'\\'
So when you said
(Pdb) p cmd
"sed -i 's/\\(panic=30\\)/\\1 ignorefs/g' /boot/bootrc"
All double backslash pairs have single backslashes. The difference with your working example in the comments is that you have literal backslashes in front of your open / closed parens.
Finally, if you don't want to worry about escaping backslashes, you can use raw strings
>>> s = r"sed -i 's/\(panic=30\)/\1 my_cool_option/g' /boot/bootrc"
>>> print s
sed -i 's/\(panic=30\)/\1 my_cool_option/g' /boot/bootrc
>>> print repr(s)
"sed -i 's/\\(panic=30\\)/\\1 my_cool_option/g' /boot/bootrc"
source to share
I see your question has been answered, but for future reference, if you have a backslash string and want to be sure it contains what you think it should, you can scan its through char to char and print it like
#! /usr/bin/env python
mystring = "this\nis\t a \complicated\\string"
print repr(mystring), len(mystring)
for i,v in enumerate(mystring):
print "%2d: %-4r %02x" % (i, v, ord(v))
Output
'this\nis\t a \\complicated\\string' 30
0: 't' 74
1: 'h' 68
2: 'i' 69
3: 's' 73
4: '\n' 0a
5: 'i' 69
6: 's' 73
7: '\t' 09
8: ' ' 20
9: 'a' 61
10: ' ' 20
11: '\\' 5c
12: 'c' 63
13: 'o' 6f
14: 'm' 6d
15: 'p' 70
16: 'l' 6c
17: 'i' 69
18: 'c' 63
19: 'a' 61
20: 't' 74
21: 'e' 65
22: 'd' 64
23: '\\' 5c
24: 's' 73
25: 't' 74
26: 'r' 72
27: 'i' 69
28: 'n' 6e
29: 'g' 67
source to share