In bash (as started by Python), I want to print this string \033[31m
so that I can use a pipe |
operator after it, followed by a command to copy that string to the clipboard. This means that in practice, I'm trying to run something like:
os.system('echo \\033[31m | xsel -ib')
...but the xsel -ib
part is working fine, so this question is focused specifically on the behavior of echo
.
Most of my attempts have been similar to:
echo -e \\033[31m
I have tried it with single quotes, double quotes, no quotes, removing the -e
flag, etc. The closest I got was:
echo -n "\\ 033[31m"
which prints this string \ 033[31m
I don't want that space between \
and 0
-n
flag is used to not append a new line after the printed string
I use Ubuntu 20.04, and xsel
is a selection and clipboard manipulation tool for the X11 Window System (which Ubuntu 20.04 uses).
CodePudding user response:
echo
is the wrong tool for the job. It's a shell builtin, and one for which the POSIX sh standard explicitly does not guarantee portable behavior for when escape sequences (such as \033
) are present. system()
starts /bin/sh
instead of bash, so POSIX behavior -- not that of your regular interactive shell -- is expected.
Use subprocess.run()
instead of os.system()
, and you don't need echo
in the first place.
If you want to put an escape sequence into the clipboard (so not \033
but instead the ESC key that this gets converted to by an echo
with XSI extensions to POSIX):
# to store \033 as a single escape character, use a regular Python bytestring
subprocess.run(['xsel', '-ib'], input=b'\033[31m')
If you want to put the literal text without being interpreted (so there's an actual backslash and an actual zero), use a raw bytestring instead:
# to store \033 as four separate characters, use a raw string
subprocess.run(['xsel', '-ib'], input=rb'\033[31m')
For a more detailed description of why echo
causes problems in this context, see the excellent answer by Stephane to the Unix & Linux Stack Exchange question Why is printf
better than echo
?.
If you for some reason do want to keep using a shell pipeline, switch to printf
instead:
# to store \033 as four separate characters, use %s
subprocess.run(r''' printf '%s\n' '\033[31m' | xsel -ib ''', shell=True)
# to store \033 as a single escape character, use %b
subprocess.run(r''' printf '%b\n' '\033[31m' | xsel -ib ''', shell=True)