So in bash, When I do

echo \*

This seems right, as * is escaped and taken literally.

But I can't understand that, when I do

echo \\*

I thought the first backslash escaped the second one thus two backslash "\\" will give me one "\" in literal. and * followed carrying its special meaning. I was expecting:

echo \\*
\file1 file2 file3

ANSWER SUMMARY: Since \ is taken literally, echo \* will behave just as echo a*, which will find any file that starts with literal "a".

Follow up question, If I want to print out exactly like

\file1 file2 file3

What command should I use? e.g. like the following but I want no space

echo \\ * 
\ file1 file2 file3

7 Answers 7


If you don't have a file in the current directory whose name starts with a backslash, this is expected behaviour. Bash expands * to match any existing file names, but:

If the pattern does not match any existing filenames or pathnames, the pattern string shall be left unchanged.

Because there was no filename starting with \, the pattern was left as-is and echo is given the argument \*. This behaviour is often confusing, and some other shells, such as zsh, do not have it. You can change it in Bash using shopt -o failglob, which will then give an error as zsh does and help you diagnose the problem instead of misbehaving.

The * and ? pattern characters can appear anywhere in the word, and characters before and after are matched literally. That is why echo \\* and echo \\ * give such different output: the first matches anything that starts with \ (and fails) and the second outputs a \, and then all filenames.

The most straightforward way of getting the output you want safely is probably to use printf:

printf '\\'; printf "%s " *

echo * is unsafe in the case of unusual filenames with - or \ in them in any case.

  • Is there any shells except zsh print the error message if matching fail by default?
    – cuonglm
    Mar 11, 2015 at 7:38
  • fish, at least. Maybe others, although I don't recall off-hand. Mar 11, 2015 at 7:57
  • @cuonglm It comes from csh and was adopted by zsh and fish. Mar 11, 2015 at 22:24
  • (1) The question says “like … echo \\ * … but I want no space”.  Your answer fails because it doesn’t include the newline at the end.  (Of course you can fix that by adding ; echo or ; printf '\n'.)  (2) Why do you use single quotes for one string and double quotes for the other? Aug 28, 2018 at 4:00
  • The printf command given will print a trailing space, and will not print a trailing newline. It's sort of an academic question at that point anyway, but it's worth mentioning those caveats.
    – Wildcard
    Oct 8, 2019 at 0:01

Try this:

printf "\\%s" "$(echo *)"


  • printf takes a format argument and zero or more arguments that are substituted into the format string
  • \\ in the format has the same meaning as in echo \\
  • %s means take the next argument and substitute it into the result
  • "$(echo *)"means: execute echo *, and put the result into a single argument to printf; it has to be put into a single argument because of how printf works
  • 1
    (1) The question says “like … echo \\ * … but I want no space”.  Your answer fails because it doesn’t include the newline at the end.  … … … … … …  (Of course you can fix that by saying printf "\\%s\n" "$(echo *)".) … … …  (2) You could change \\ to \ in your answer (printf "\%s" "$(echo *)"), and it would work as well.  … … … …  … … …  … …  (3) Also, as far as I can tell, echo "\\$(echo *)" would work as well.  … (Cont’d) Aug 28, 2018 at 4:08
  • 1
    (Cont’d) …  (4) The real problem with this answer is that it depends on the mercurial behavior of echo. If there is a file named -e or -n (and it is the first file in the * list), it will disappear. Aug 28, 2018 at 4:10


set file*
printf %s\  "\\$@"

It will prepend a a backslash to the head of the array - so only the first element. You can do the same with the end. You can get get them all split out on \\ backslashes like:

printf \\%s file*


set file*; IFS=\\; printf %s\\n "$*"
  • (1) The question says “like … echo \\ * … but I want no space”. Your answer fails because it doesn’t include the newline at the end. (It seems especially odd that you missed this, since you included a trailing newline in the last line of your answer, where you’re answering a different question.) (2) Since your answer uses set, it should be put into a subshell, to avoid setting / changing the positional parameters in an outer scope / context. … (Cont’d) Aug 28, 2018 at 4:10
  • (Cont’d) …  (3) The question talks about echo … *, and indicates that the current directory contains file1, file2, and file3. (Arguably, we should treat these as placeholders rather than examples.) Using file* in your answer seems inappropriate. (4) So, any correct answer should include a plain *. Making the appropriate change to your answer, we get set *, which can fail if there is a file whose name begins with - (dash). … (Cont’d) Aug 28, 2018 at 4:10
  • (Cont’d) …  (5) Why use $@ and a literal space in the format string when you could use $* and let the shell interpolate space(s) for you? (OK, yes, I know about IFS.) (6) People less clever and tricky than you might not realize that you are using a literal space in the format string because it isn’t quoted. A good answer would make a detail like that explicit, and explain it. Aug 28, 2018 at 4:10
  • @Scott - actually, literal space is between the lines. the space character in the format string is quoted, though.
    – mikeserv
    Aug 28, 2018 at 11:58

No, bash escape character preserves the literal value of the next character that follows, from left to right, so \\* give you pattern \*.

This pattern is performed Filename Expansion, with the Pattern Matching rules.

So \* is interpret as all files starting with \ and follows by anything. In your case it matched nothing and bash left the pattern \* unchanged to echo.


I believe that all the other answers to the second half of the question (“What command should I use?”) are wrong, if only technically or in edge cases.  I believe that this addresses the problems in the other answers:

(set -- *; echo "\\$*")

and (FWIW) all the writing is being done in a single command
(unlike printf '\\'; printf "%s " *; echo).

  • Use a subshell to avoid setting / changing the positional parameters in an outer scope / context.
  • Naively, set * sets the positional parameters ($1, $2, $3, etc…) to the names of the files in the current directory.  (Filenames beginning with . (dot) are included, or not, based on whether the dotglob option is set.)
  • set * can fail if there is a file whose name begins with - (dash) (and it is the first file in the * list).  set -- * handles this; -- says “everything after this is an argument and not an option / flag.”
  • $* is the list of positional parameters ($1 $2 $3 …), with the parameters separated by space(s).  The \\ causes \ to be output at the beginning of the line, just as in the echo \\ * (example command in the question), but it doesn’t interfere with the expansion of the subsequent $*.
  • $* is the list of positional parameters ($1 $2 $3 …), with the parameters separated by the first character of $IFS.  If there’s a possibility that the first character of $IFS might not be space, do
(set -- *; IFS=" "; echo "\\$*")

Slightly more verbose options include

(set -- *; printf "%s\n" "\\$*")


(set -- *; printf "\\%s\n" "$*")

These are safer in an environment where echo might interpret backslashes in the argument strings even without an -e option.

Again, add IFS=" "; if there’s a possibility that the first character of $IFS might not be space.


1: glob

When I do echo \* I get *

This seems right, as * is escaped and taken literally.

Yes, with an escape \ (quote), an otherwise special character becomes regular and therefore is printed back as it is, a *.

But I can't understand that, when I do echo \\* I get \*

Because you need to think about "an string" to expand (via globbing). The string is \\*, which, because it is un-quoted and it has an special character (the backslash) the first backslash quotes the second and becomes one backslash followed by an asterisk (\*). The string: backslash (\) followed by anything (*) should match literally that: a file name that start with a backslash and followed by more characters. If there are no files like \a, \one or \file the globbing of \* fails, that is, it can not expand to a "list of files". If some options in bash (failglob or nullglob) are not set, the string \* remains and is printed as it was. You get \* back.

2: concatenation

I was expecting:

    $ echo \\*
    \file1 file2 file3

Above we clarified why \\* ends up being the string \*, that is: one string. There is no concatenation of two strings as in:

$ a='\'
$ b='file1 file2 file3'
$ echo "$a$b"
/file1 file2 file3

That is:you need two strings to get them concatenated. One string could be a variable of the literal \, the other could be the list of files in the present directory as an string. One way to accomplish that is:

$ set -- *               # get the list of files as arguments.
$ echo '\'"$*"           # or "\\$*".  Convert arguments to an string $*
                         # and concatenate '\' to it.
\file1 file2 file3

I ran into a special character issue which none of this seemed to resolve when attempting to transfer using one particular Windoze "direct connection" utility. So I stepped out with my caveman club and was able to make this work. The main issue was that the desitination path included an escape character prior to the dynamic filename value stored as string.

OUTPUT_FILE=`echo "my_file_name.txt"`
OUTPUT_DIR=`echo "/path/to/file/"`
xfrcmd=`echo "path_to_transferutil ${OUTPUT_DIR}${OUTPUT_FILE}" 'X:\Reports\Reconciliation"`
xfrcmd=$xfrcmd`echo "${OUTPUT_FILE}' windozefeller 'account,pass' label parm1 parm2;"`
eval $xfrcmd >logdest
  • I don’t quite understand what you’re doing (i.e., what you’re accomplishing; what problem you’re trying to solve).  And, maybe, if I understood that, I’d understand how this relates to the question — but I don’t.  Please do not respond in comments; edit your answer to make it clearer and more complete. P.S. Why do you say var=`echo value` instead of var=value? Aug 27, 2018 at 23:32
  • The problem being solved is that with the straightforward assignment of the value and with a variable name included in the windows path building, the backslash prior to the name of the var is stripped from the path. The use of the echo command in building the command to be executed and breaking it in the middle manually to force that slash to come appended to the string before completing the assignment and executing works fine. Escaping the character in the string assignment is not as straightforward as it's been presented here and in all cases.
    – omichaud
    Aug 29, 2018 at 19:19

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .