139

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.

6
  • 7
    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. Commented May 18, 2010 at 5:01
  • 2
    possible duplicate of echo that shell-escapes arguments
    – P Shved
    Commented May 18, 2010 at 5: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
    Commented Nov 2, 2018 at 4:02
  • 2
    The question was specific to using \\ for \. There is an accepted answer.
    – User1
    Commented Nov 2, 2018 at 20:04
  • Perhaps make the title more specific? (But *** *** *** *** *** without *** *** *** *** *** "Edit:", "Update:", or similar - the question should appear as if it was written today.) Commented Aug 16, 2023 at 18:30

6 Answers 6

211

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
8
  • 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 stackoverflow.com/a/20053121/1073695
    – Jo So
    Commented Oct 22, 2015 at 1:49
  • 3
    sed is indeed better because can escape dollar signs too
    – untore
    Commented Jul 24, 2016 at 11:05
  • 3
    @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? Commented Jul 27, 2016 at 16:21
  • 4
    to escape the dollar sign just use single quotes instead, eg: printf "%q" 'he$l&lo\world'
    – lrepolho
    Commented Mar 28, 2017 at 4:39
  • 1
    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. Commented Apr 29, 2019 at 16:18
18

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?

15

Pure Bash, use parameter substitution:

string="Hello\ world"
echo ${string//\\/\\\\} | someprog
2
  • 1
    this way "hello world" is not escaped to "hello\ world" - printf aproach in accepted answer does that.
    – Christoph
    Commented Jan 24, 2016 at 21:01
  • This allows adding escape sequence to strings to be used at sed like commands Commented Jan 5, 2023 at 0:28
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;
}
1
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.

2
  • 1
    Why not sed? $echo "hello\ world" |sed 's/\\/\\\\/'
    – Space
    Commented May 18, 2010 at 5:17
  • 1
    @Octopus, that is also a valid option. I happen to be more comfortable with perl, but yeah, that works, too. Commented May 18, 2010 at 5:35
0

I could escape string with creating a function of bash.

function escape_str () {
  echo "$1" | sed 's/\\/\\\\/g' | sed 's/\"/\\"/g'
}

STR_JSON="{\"num\": 5}"

echo $STR_JSON
# shows {"num": 5}

ESCAPED_STR_JSON=$(escape_str "$STR_JSON")
echo $ESCAPED_STR_JSON
# shows {\"num\": 5}

DOUBLE_ESCAPED_STR_JSON=$(escape_str "$ESCAPED_STR_JSON")
echo $DOUBLE_ESCAPED_STR_JSON
# shows {\\\"num\\\": 5}

Not the answer you're looking for? Browse other questions tagged or ask your own question.