Command to escape a string in Bash
Asked Answered
R

6

136

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.

Ruberta answered 18/5, 2010 at 4:58 Comment(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.Jewel
possible duplicate of echo that shell-escapes argumentsFiddlededee
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.Word
The question was specific to using \\ for \. There is an accepted answer.Ruberta
Perhaps make the title more specific? (But *** *** *** *** *** without *** *** *** *** *** "Edit:", "Update:", or similar - the question should appear as if it was written today.)Abysmal
Related: How to escape single quotes within single quoted stringsAbysmal
I
210

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
Insnare answered 18/5, 2010 at 9:35 Comment(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 https://mcmap.net/q/12295/-which-characters-need-to-be-escaped-when-using-bashAmyl
sed is indeed better because can escape dollar signs tooTonjatonjes
@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?Insnare
to escape the dollar sign just use single quotes instead, eg: printf "%q" 'he$l&lo\world'Excerpta
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.Lacefield
@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.Insnare
how would I adapt this for a pipe? echo "hello\world" | printf "%q" wouldn't do itSymer
@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.Insnare
L
14

Pure Bash, use parameter substitution:

string="Hello\ world"
echo ${string//\\/\\\\} | someprog
Lamarre answered 18/5, 2010 at 6:40 Comment(2)
this way "hello world" is not escaped to "hello\ world" - printf aproach in accepted answer does that.Ernieernst
This allows adding escape sequence to strings to be used at sed like commandsStrophic
A
14

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?

Atheistic answered 11/7, 2021 at 3:2 Comment(0)
S
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;
}
Sension answered 17/12, 2020 at 6:54 Comment(1)
Here's a C++ adaptation of the above: godbolt.org/z/WK8Y175G8Planter
J
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.

Jewel answered 18/5, 2010 at 5:4 Comment(2)
Why not sed? $echo "hello\ world" |sed 's/\\/\\\\/'Garrygarson
@Octopus, that is also a valid option. I happen to be more comfortable with perl, but yeah, that works, too.Jewel
C
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}
Cassella answered 25/2 at 13:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.