132

I need a Bash command that will convert a string to something that is escaped. Here's an example:

echo "hello\world" | escape | someprog

Where the escape command makes "hello\world" into "hello\\\world". Then, someprog can use "hello\\world" as it expects. Of course, this is a simplified example of what I will really be doing.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
User1
  • 39,458
  • 69
  • 187
  • 265
  • 6
    What is the nature of the escape? In other words, what characters need to be escaped? Are you looking for a C++-style escape (where tabs are replaced by \t, newlines with \n, quotes with \", etc.)? It is hard to help without the problem being well-defined. – Michael Aaron Safyan May 18 '10 at 05:01
  • 2
    possible duplicate of [echo that shell-escapes arguments](http://stackoverflow.com/questions/2731883/echo-that-shell-escapes-arguments) – P Shved May 18 '10 at 05:04
  • This question could mean any of a dozen different things. Instead of making us guess, it would help if you state exactly what kind of escaping you're looking for. – Don Hatch Nov 02 '18 at 04:02
  • 2
    The question was specific to using \\ for \. There is an accepted answer. – User1 Nov 02 '18 at 20:04
  • Perhaps make the title more specific? (But *** *** *** *** *** ***[without](https://meta.stackexchange.com/a/131011)*** *** *** *** *** *** "Edit:", "Update:", or similar - the question should appear as if it was written today.) – Peter Mortensen Aug 16 '23 at 18:30
  • Related: *[How to escape single quotes within single quoted strings](https://stackoverflow.com/questions/1250079/)* – Peter Mortensen Aug 16 '23 at 18:31

5 Answers5

207

In Bash:

printf "%q" "hello\world" | someprog

for example:

printf "%q" "hello\world"
hello\\world

This could be used through variables too:

printf -v var "%q\n" "hello\world"
echo "$var"
hello\\world
skywinder
  • 21,291
  • 15
  • 93
  • 123
Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439
  • 8
    Mind you, `%q` was broken for more than a decade until about 2012. It had problems with `~`. There are also portable sed one-liners http://stackoverflow.com/a/20053121/1073695 – Jo So Oct 22 '15 at 01:49
  • 3
    sed is indeed better because can escape dollar signs too – untore Jul 24 '16 at 11:05
  • 2
    @untore: `a='abc$def":'; printf '%q\n' "$a"` results in `abc\$def\":` (the dollar sign is escaped). This is Bash 4.3 (I got the same result in Bash 3.2). What version are you using? – Dennis Williamson Jul 27 '16 at 16:21
  • 4
    to escape the dollar sign just use single quotes instead, eg: `printf "%q" 'he$l&lo\world'` – lrepolho Mar 28 '17 at 04:39
  • bash's `printf '%q\n' text` quotes the text in `bash` format (and for the current locale), so that would only work in the OP's case if their `someprog` had the exact same quoting syntax as `bash` which is highly unlikely. – Stephane Chazelas Apr 29 '19 at 16:18
  • @StephaneChazelas: What you say is true, but the OP accepted the answer almost 9 years ago and then reiterated the acceptance in a comment below the question just this last November. – Dennis Williamson Apr 29 '19 at 17:21
  • how would I adapt this for a pipe? `echo "hello\world" | printf "%q"` wouldn't do it – Sridhar Sarnobat Apr 03 '20 at 20:37
  • 1
    @SridharSarnobat: One way would be to use a loop: `... | while read -r line; do printf '%q' "$line"; done`. Add a `\n` to the format specifier if needed. – Dennis Williamson Jun 28 '22 at 20:48
12

Pure Bash, use parameter substitution:

string="Hello\ world"
echo ${string//\\/\\\\} | someprog
Fritz G. Mehner
  • 16,550
  • 2
  • 34
  • 41
10

The Bash builtin ${…@Q} expansion has been added some time ago:

echo "hello\\world" | ( read -rsd '' x; echo ${x@Q} )
'hello\world'

The escaped output is in bash format, so it might not be what you need.

See also: Which characters need to be escaped when using Bash?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Caesar
  • 6,733
  • 4
  • 38
  • 44
3

It may not be quite what you want, since it's not a standard command on anyone's systems, but since my program should work fine on POSIX systems (if compiled), I'll mention it anyway. If you have the ability to compile or add programs on the machine in question, it should work.

I've used it without issue for about a year now, but it could be that it won't handle some edge cases. Most specifically, I don't have any idea what it would do with newlines in strings; a case for \\n might need to be added. This list of characters is not authoritative, but I believe it covers everything else.

I wrote this specifically as a 'helper' program, so I could make a wrapper for things like scp commands.

It can likely be implemented as a shell function as well.

I therefore present escapify.c. I use it like so:

scp user@host:"$(escapify "/this/path/needs to be escaped/file.c")" destination_file.c

Please note: I made this program for my own personal use. It also will (probably wrongly) assume that if it is given more than one argument that it should just print an unescaped space and continue on. This means that it can be used to pass multiple escaped arguments correctly, but it could be seen as unwanted behavior by some.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
  char c='\0';
  int i=0;
  int j=1;
  /* Do not care if no arguments are passed; escaped nothing is still nothing. */
  if(argc < 2)
  {
    return 0;
  }
  while(j<argc)
  {
    while(i<strlen(argv[j]))
    {
      c=argv[j][i];
      /* This switch has no breaks on purpose. */
      switch(c)
      {
      case ';':
      case '\'':
      case ' ':
      case '!':
      case '"':
      case '#':
      case '$':
      case '&':
      case '(':
      case ')':
      case '|':
      case '*':
      case ',':
      case '<':
      case '>':
      case '[':
      case ']':
      case '\\':
      case '^':
      case '`':
      case '{':
      case '}':
        putchar('\\');
      default:
        putchar(c);
      }
      i++;
    }
    j++;
    if(j<argc) {
      putchar(' ');
    }
    i=0;
  }
  /* Newline at the end */
  putchar ('\n');
  return 0;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Wyatt Ward
  • 1,056
  • 12
  • 18
0

You can use Perl to replace various characters, for example:

echo "Hello\ world" | perl -pe 's/\\/\\\\/g'

Output:

Hello\\ world

Depending on the nature of your escape, you can chain multiple calls to escape the proper characters.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Michael Aaron Safyan
  • 93,612
  • 16
  • 138
  • 200