How can I protect parentheses passed to a cd command? [duplicate]

I asked here how to make cd protect spaces. Tab completion is great, but sometimes you paste the path from the clipboard so this is useful.

The solution breaks with parentheses however. No matter how you try to escape and protect the input it always returns:

bash: syntax error near unexpected token `('

Is there some way to have it also deal with parentheses? What I want is that when I enter this, it works:

cd My path with spaces (and parentheses)

Solution 1:

Use single quotes ' around the argument. (This works for any command, not just cd).

cd 'My path with spaces (and parentheses)'

You can't make bash pass the parentheses to cd. Getting the spaces to work at all is a very specialized hack.

Single quotes work around every character except ' itself. Replace single quotes by the 4-character sequence '\''.

cd 'Apostrophe'\''s a pain'

This doesn't work if the directory name begins with a hyphen, because that causes the cd command to interpret the argument as an option. Pass -- before the directory name to avoid this.

See https://unix.stackexchange.com/questions/69144/how-do-i-escape-a-sub-directory-name-with-an-ampersand-in-it/69147#69147 for more details.

Another method is to have the shell read a separate line of text instead of passing the argument on the command line.

Strapakowsky@darkstar ~$ read -r; cd -- "$REPLY"
My path with spaces (and parentheses)
Strapakowsky@darkstar ~/My path with spaces (and parentheses)$ 

Rather than copy-paste manually, you might as well do it programmatically. Install either xclip or xsel.

cd -- "$(xclip -o -selection clipboard)"
cd -- "$(xsel -bo)"

You might make this an alias.

alias cde='cd -- "$(xsel -bo)"'

Solution 2:

How to correctly cd to directories with characters like spaces and parentheses in their names:

If your folder name doesn't include a single-quote character ', just enclose it in single quotes:

cd 'My path with spaces (and parentheses)'

If it does include a ', but doesn't include a double quote character ", a backlash \, a backquote ` or a dollar $, enclose it in double quotes:

cd "My path with spaces (and parentheses)"

It's not very common for a file or directory name to contain both single and double quotes. (This is perhaps due to how it's not common for a file or directory name to contain double quotes at all. The only reason I didn't recommend double quotes originally is that, unlike single quotes, double quotes allow the $ to expand environment variables. This would be a problem if your filename contained a $ character followed by text.)

If it contains both, or you just want another method, then you can escape each space and parenthesis manually by inserting a backslash character \ before it:

cd My\ path\ with\ spaces\ \(and parentheses\)

That's annoying, but fortunately, the shell with do it for you, if you type the beginning of the name and press Tab. If there is more than one file or directory name that starts with My, then you might need to type some more to get it to expand. If you press Tab and it doesn't expand you can press Tab again to see a list of files that match what you've typed so far. Then you know how much more you must type to get it to match uniquely and expand.

Alternatively, you could escape the internal quotes. For example, suppose you had a folder called:

Mischa's gardening tips for "home and office"

You can use:

cd Mischa\'s\ gardening\ tips\ for\ \"home\ and\ office\"

But you can also simply use:

cd 'Mischa'\''s gardening tips for "home and office"'

Backslashes aren't special inside single quotes, so we terminate the single-quoted string, append a backslash-protected single quote, and immediately start another single-quoted string, all without any space that would start a separate argument.

Why you probably cannot make cd work the way you wanted it to:

As for getting cd My path with spaces (and parentheses) to work: no, you really cannot do that, because this behavior is not specific to the cd command, it is part of the way running any command works. When a command is run, it is give a list of arguments provided by the user. When the shell sees a space, it knows one argument has just ended and another has just begun. To pass a space as part of an argument it must be quoted in one of the above ways.

You could achieve part of this some of the time--you could make cd My path with spaces work to go into the My path with spaces folder. You could achieve this by writing a shell script that concatenates all its user-provided arguments with spaces. (Then if you wanted you could make cd itself call that script, by creating a shell alias named cd for it; that would take precedence over the shell builtin cd which you currently are ordinarily running.) But:

  • The script would not receive different arguments for My path with spaces and My path with spaces, so cd My path with spaces would fail or enter the wrong folder.

  • You could not do this for the parentheses, because these are used for grouping by the shell such that they are not communicated in any way to a command. Actually, most of the time the shell will simply throw a syntax error (just as you have seen):

    ek@Kip:~$ cd My path with spaces (and parentheses)
    bash: syntax error near unexpected token `('
    

    No matter what you change, that syntax error will continue to occur when that command is given.

I say that you "probably" cannot make this work because there is one way that will--you can make your own shell that behaves as you wish. But this is extremely difficult and it's unlikely that anyone would want to do that, just to make this change. (You could also modify the source code of an existing shell, which is a more practical solution but still requires more effort than most people would want to exert.) Besides that, it's unlikely that cd can accept directory names with arbitrary characters including spaces in them, like it does on Windows.

In case you're wondering why this works on Windows but not in Ubuntu: In Windows, commands are passed the text typed after them as a string of text, and when a command needs to interpret that string as a sequence of separate arguments (which it usually, but not always, does), the code for the command must call a special library function that parses the command-line string. (In a C program, this happens behind the scenes, but still involves using the Windows API.)