116

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.

Mateen Ulhaq
  • 21,459
  • 16
  • 82
  • 123
User1
  • 37,405
  • 65
  • 180
  • 257
  • 5
    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
  • 1
    The question was specific to using \\ for \. There is an accepted answer. – User1 Nov 02 '18 at 20:04

5 Answers5

186

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
  • 20,913
  • 15
  • 90
  • 122
Dennis Williamson
  • 324,833
  • 88
  • 366
  • 429
  • 6
    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
  • 3
    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
8

Pure Bash, use parameter substitution:

string="Hello\ world"
echo ${string//\\/\\\\} | someprog
Fritz G. Mehner
  • 15,718
  • 2
  • 32
  • 41
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 have no 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 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 args 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 end */
  putchar ('\n');
  return 0;
}
Wyatt Ward
  • 965
  • 10
  • 18
2

A bash buitin 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: https://stackoverflow.com/a/27817504/401059

Caesar
  • 3,590
  • 2
  • 27
  • 40
0

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

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

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

Michael Aaron Safyan
  • 90,931
  • 15
  • 133
  • 196