How to cd into a directory with space in the name? - bash

I'm attempting to get into the directory /cygdrive/c/Users/my dir/Documents:
$ DOCS="/cygdrive/c/Users/my\ dir/Documents"
$ echo $DOCS
/cygdrive/c/Users/my\ dir/Documents
$ cd $DOCS
-bash: cd: /cygdrive/c/Users/my\: No such file or directory
$ cd /cygdrive/c/Users/my\ dir/Documents
(success)
When I manually type it in, the backspace does its escape character thing, but not when I use parameter expansion with the variable DOCS.
I tried other variations such as no backslash.
$ DOCS=/cygdrive/c/Users\ dir/Documents
$ echo $DOCS
/cygdrive/c/Users/my dir/Documents
$ cd $DOCS
-bash: cd: /cygdrive/c/Users/my: No such file or directory
or
$ DOCS="/cygdrive/c/Users/my dir/Documents"
$ echo $DOCS
/cygdrive/c/Users/my dir/Documents
$ cd $DOCS
-bash: cd: /cygdrive/c/Users/my: No such file or directory
The same happens for $HOME:
$ echo $HOME
/home/my dir
cd $HOME doesn't work either. Quotes must be put around it.
What the heck:
$ DOCS="\"/cygdrive/c/Users/my dir/Documents\""
$ echo $DOCS
"/cygdrive/c/Users/my dir/Documents"
$ cd $DOCS
-bash: cd: "/cygdrive/c/Users/my: No such file or directory

$ cd "$DOCS"
You need to quote "$DOCS" to prevent spaces from being parsed as word separators. More often than not, variable references should be quoted.
Note that $HOME would have the same problem. The issue is coming from when the shell evaluates variable references; it's nothing to do with what variables you use or how you assign to them. It's the expansion that needs to be quoted.
$ echo $HOME
/home/my dir
This is deceptive. echo is actually echoing the two strings /home/my and dir. If you use cd or ls you'll see how it's actually working.
$ ls $HOME
ls: cannot access /home/my: No such file or directory
ls: cannot access dir: No such file or directory
$ cd $HOME
bash: cd: /home/my: No such file or directory
$ cd "$HOME"
<success!>
Can I ask why it works when I manually type it in but not in a variable?
Great question! Let's examine the commands you typed:
$ DOCS="\"/cygdrive/c/Users/my dir/Documents\""
$ echo $DOCS
"/cygdrive/c/Users/my dir/Documents"
$ cd $DOCS
-bash: cd: "/cygdrive/c/Users/my: No such file or directory
The reason this doesn't work is because Bash doesn't parse quotes inside variable expansions. It does perform word splitting, so whitespace in unquoted variable expansions is taken as word separators. It doesn't parse quotes in any way, meaning you can't put double quotes inside a variable to override word splitting.
$ cd $DOCS
Because of this, cd is passed two parameters. As far as cd knows it looks like you wrote:
$ cd '"/cygdrive/c/Users/my' 'dir/Documents"'
Two parameters, with double quotes intact.

SOLUTION:
cd "Documents and Photos"
problem solved.
The reason I'm submitting this answer is you'll find that StackOverflow is being used by every day users (not just web devs, programmers or power users) and this was the number one result for a simple Windows user question on Google.
People are becoming more tech-savvy, but aren't necessarily familiar with command line in the cases above.

To change to a directory with spaces on the name you just have to type like this:
cd My\ Documents
Hit enter and you will be good

$ DOCS="/cygdrive/c/Users/my\ dir/Documents"
Here's your first problem. This puts an actual backslash character into $DOCS, as you can see by running this command:
$ echo "$DOCS"
/cygdrive/c/Users/my\ `
When defining DOCS, you do need to escape the space character. You can quote the string (using either single or double quotes) or you can escape just the space character with a backslash. You can't do both. (On most Unix-like systems, you can have a backslash in a file or directory name, though it's not a good idea. On Cygwin or Windows, \ is a directory delimiter. But I'm going to assume the actual name of the directory is my dir, not my\ dir.)
$ cd $DOCS
This passes two arguments to cd. The first is cygdrive/c/Users/my\, and the second is dir/Documents. It happens that cd quietly ignores all but its first argument, which explains the error message:
-bash: cd: /cygdrive/c/Users/my\: No such file or directory
To set $DOCS to the name of your Documents directory, do any one of these:
$ DOCS="/cygdrive/c/Users/my dir/Documents"
$ DOCS='/cygdrive/c/Users/my dir/Documents'
$ DOCS=/cygdrive/c/Users/my\ dir/Documents
Once you've done that, to change to your Documents directory, enclose the variable reference in double quotes (that's a good idea for any variable reference in bash, unless you're sure the value doesn't have any funny characters):
$ cd "$DOCS"
You might also consider giving that directory a name without any spaces in it -- though that can be hard to do in general on Windows.

Use quotes!
cd "Name of Directory"
Or you can go to the file explorer and click "copy path" in the top left corner!

Cygwin has issue recognizing space in between the PC name. So to solve this, you have to use "\" after the first word then include the space, then the last name.
such as ".../my\ dir/"
$ cd /cygdrive/c/Users/my\ dir/Documents
Another interesting and simple way to do it, is to put the directory in quotation marks ("")
e.g
run it as follows:
$ cd c:
$ cd Users
$ cd "my dir"
$ cd Documents
Hope it works?

If you want to CD into a path where the directory with space comes in between. You can wrapped the entire path into quotes.
cd "C:\Users\JOE\Local Sites\skeleton"

try
DOCS="/cygdrive/c/Users/my\ dir/Documents";
cd "$DOCS"

Why not put the following in your .cshrc (or .bashrc, or whatever your default shell is):
alias mydoc 'cd "/cygdrive/c/Users/my dir/Documents"'
First time you do this, you have to do
source .cshrc
to update the shell with this new alias, then you can type
mydoc
anytime you want to cd to your directory.
Laziness is the mother of invention...

If you want to move from c:\ and you want to go to c:\Documents and settings, write on console: c:\Documents\[space]+tab and cygwin will autocomplete it as c:\Documents\ and\ settings/

Use the backslash symbol (\) to escape the space:
C:\> cd my folder
will be
C:\> cd my\ folder

ok i spent some frustrating time with this problem too. My little guide.
Open desktop for example. If you didnt switch your disc in cmd, type:
cd desktop
Now if you want to display subfolders:
cd, make 1 spacebar, and press tab 2 times
Now if you want to enter directory/file with SPACE IN NAME. Lets open some file name f.g., to open it we need to type:
cd file\ name
p.s. notice this space after slash :)

METHOD1: With Quotes
cd "C:/Prgram Files (x86)"
cd 'C:/Program Files (x86)'
Generalised
cd 'Folder Path'
Method2: Without using Quotes
cd Program\ Files \(x86\)
Generalised
Whenever we want to skip next character we use blackslash \.
For the above question:
cd /cygdrive/c/Users/my\ dir/Documents

As an alternative to using quotes, for a directory you want to go to often, you could use the cdable_vars shell option:
shopt -s cdable_vars
docs='/cygdrive/c/Users/my dir/Documents'
Now, to change into that directory from anywhere, you can use
cd docs
and the shell will indicate which directory it changed to:
$ cd docs
/cygdrive/c/Users/my dir/Documents

The approaches discussed here don't work for aliases in a consistent basis - adding/not adding quotes etc.
E.g. if I have a directory variable like dir_with_spaces='path of the directory with spaces', it is not possible to directly use alias new_dir='cd $dir_with_spaces/subdirectory'.
As an alternative, it would be useful to create a custom function that adds quotes around the cd, and then use this custom function instead.
cdwq() # Custom cd to support directories with spaces in the name by adding quotes around it
{
local folder_path=$1
cd "${folder_path}"
}
Now, it is possible to use this custom function with any directory variable.
dir_with_spaces='path of the directory with spaces'
dir_without_spaces='path_of_the_directory_without_spaces'
alias new_dir1='cdwq $dir_with_spaces/subdirectory1'
alias new_dir2='cdwq $dir_with_spaces/subdirectory2'
alias new_dir3='cdwq $dir_without_spaces/subdirectory3'
alias new_dir4='cdwq $dir_without_spaces/subdirectory4'
alias new_dir5='cdwq $dir_with_spaces/subdirectory5'

If there is space inside dir name, you can use wild card character (? or *) in place of space & wrap the directory name in double-quotes.
Example - in the below path, "Program Files" has space inside -
/mnt/c/Program Files$ JAVA_HOME=/mnt/c/"Program?Files"/Java/jdk-11.0.12
/mnt/c/Program Files$ cd $JAVA_HOME
/mnt/c/Program Files/Java/jdk-11.0.12$

Just use quotes around the file that has a space in it
cd "file with space"

Instead of:
DOCS="/cygdrive/c/Users/my\ dir/Documents"
Try:
DOCS="/cygdrive/c/Users/my dir/Documents"
This should work on any POSIX system.

Related

~/.zshrc alias with a space

I have a bad habit of putting spaces in my folder/file names. Today it bites me.
I have a folder called NFB Lab in which I installed NFB Lab. I wanted to add the shortcut/command nfb and pynfb to the ~/.zshrc file to start the main python script from anywhere.
I edited the ~/.zshrc file through nano with:
alias nfb=/Users/mathieu/Documents/NFB\ Lab/pynfb/main.py
alias pynfb=/Users/mathieu/Documents/NFB\ Lab/pynfb/main.py
I also tried:
alias nfb="/Users/mathieu/Documents/NFB Lab/pynfb/main.py"
alias pynfb="/Users/mathieu/Documents/NFB Lab/pynfb/main.py"
Neither works, I always get:
zsh: no such file or directory: /Users/mathieu/Documents/NFB
How can I solve this without uninstall/reintsall of NFB Lab?
You'll need to escape the space (\ ), for example, take a look at my sublimetext3 alias;
alias sub='/Applications/Sublime\ Text.app/Contents/SharedSupport/bin/subl'
Otherwise, take a look at ZSH functions. There are many more options compared to aliasses;
For example, run python script with arg as path, then create an alias calling that function
function runpy() {
python3 "$#"
}
alias runx="runpy '/tmp/dir with space/py.py'"
alias runy="runpy '/tmp/dir with space/py_second.py'"
You need two backslashes.
$ mkdir "f oo"
$ alias f="cd f\\ oo"
$ f
$ pwd
/home/foobar/tmp/f oo
Considering the confusion caused by backslash inside single or double quotes, here is one alternative :
alias nfb="'/Users/mathieu/Documents/NFB Lab/pynfb/main.py'"
alias pynfb="'/Users/mathieu/Documents/NFB Lab/pynfb/main.py'"

Why can't I 'cd' into Bash aliases on Cygwin?

I'm using Bash via the mintty terminal on Cygwin, and I've created two aliases in my .bashrc file in my Cygwin home directory.
alias croot="C:/cygwin64"
alias desktop="B:/Users/User/Desktop"
When I enter croot or desktop into the terminal, it seems to work fine:
B:/Users/User/Desktop: Is a directory
However, using those aliases with something like cd croot returns the error:
-bash: cd: croot: No such file or directory
What's going on here?
alias doesn’t work the way you think it does. Do this:
alias croot='cd C:/cygwin64'
croot
Or:
croot=C:/cygwin64
cd "$croot"
Result:
$ pwd
/
There is a way to make this work. But I would not recommend it. Use steven's answer instead.
$ help alias
alias: alias [-p] [name[=value] ... ]
Define or display aliases.
Without arguments, 'alias' prints the list of aliases in the reusable
form 'alias NAME=VALUE' on standard output.
Otherwise, an alias is defined for each NAME whose VALUE is given.
A trailing space in VALUE causes the next word to be checked for
alias substitution when the alias is expanded.
Options:
-p print all defined aliases in a reusable format
Exit Status:
alias returns true unless a NAME is supplied for which no alias has been
defined.
$ alias croot="C:/cygwin64"
$ alias desktop="B:/Users/User/Desktop"
$ alias cd='builtin cd ' # Notice the trailing space.
$ cd croot; pwd
/
Note that only the word immediately next to cd will be considered for alias expansion. Hence cd -P croot will not work.

shell script to copy files from one directory to another

Trying to write a simple script to copy some files in OS X 10.9.
Here's the content..
SRC_DIR="~/Library/Preferences-Old"
DST_DIR="~/Library/Preferences"
FILEN="test.txt"
cp $SRC_DIR/$FILEN $DST_DIR
Gives me the output:
cp: ~/Library/Preferences-Old/test.txt: No such file or directory
Of course, the above is wrong. The exact same cp command in terminal directly does the trick. What am I doing wrong here?
~ is one of the few exceptions to the rule "When in doubt, quote". As others have pointed out, a quoted ~ is not subject to expansion. However, you can still quote the rest of the string:
SRC_DIR=~"/Library/Preferences-Old"
DST_DIR=~"/Library/Preferences"
Note that depending on the values assigned to the two *_DIR variables, it's not enough to quote the values being assigned; you still need to quote their expansions.
FILEN="test.txt"
cp "$SRC_DIR/$FILEN" "$DST_DIR"
Your double-quotes are preventing the shell from converting your ~ into an actual path. Observe:
$ echo ~
/home/politank_z
$ echo "~"
~
~ isn't an actual location, it is shorthand for the path of your home directory.
As already mentioned double-quotes disabled ~ expansion.
Better approach is to use HOME variable:
SRC_DIR="$HOME/Library/Preferences-Old"
DST_DIR="$HOME/Library/Preferences"

command substitution but without breaking output into multiple arguments

Is there a way to do command substitution in BASH shell without breaking output into multiple arguments?
I copy the path of some directory (from the location bar in a GUI file browser) to clipboard and then issue the following command, where the command xsel returns the clipboard content, which is the path of the directory in this case:
cd `xsel`
But some path contain spaces or may even contain some special characters used by BASH.
How can I pass the output of a command as a single argument and without BASH messing with special characters?
cd "$(xsel)"
seems to handle all special characters (including $ and spaces).
My test string was boo*;cd.*($\: $_
$ mkdir "$(xsel)"
$ ls
boo*;cd.*($\: $_
$ file boo\*\;cd.\*\(\$\\\:\ \$_/
boo*;cd.*($\: $_/: directory
$ cd "$(xsel)"
$ pwd
/tmp/boo*;cd.*($\: $_
Have you tried:
cd "`xsel`"
That should do the job, unless you have dollars($) or back-slashes (\) in your path.
If you aren't doing this programmatically, most terminals in Linux let you paste from the clipboard with a middle-click on your mouse. Of course, you'll still need to put quotes before and after your paste, like #dave suggests.

Bash script to cd to directory with spaces in pathname

I'm using Bash on macOS X and I'd like to create a simple executable script file that would change to another directory when it's run. However, the path to that directory has spaces in it. How the heck do you do this? This is what I have...
Name of file: cdcode
File contents:
cd ~/My Code
Now granted, this isn't a long pathname, but my actual pathname is five directories deep and four of those directories have spaces in the path.
BTW, I've tried cd "~/My Code" and cd "~/My\ Code" and neither of these worked.
When you double-quote a path, you're stopping the tilde expansion. So there are a few ways to do this:
cd ~/"My Code"
cd ~/'My Code'
The tilde is not quoted here, so tilde expansion will still be run.
cd "$HOME/My Code"
You can expand environment variables inside double-quoted strings; this is basically what the tilde expansion is doing
cd ~/My\ Code
You can also escape special characters (such as space) with a backslash.
I found the solution below on this page:
x="test\ me"
eval cd $x
A combination of \ in a double-quoted text constant and an eval before cd makes it work like a charm!
After struggling with the same problem, I tried two different solutions that works:
1. Use double quotes ("") with your variables.
Easiest way just double quotes your variables as pointed in previous answer:
cd "$yourPathWithBlankSpace"
2. Make use of eval.
According to this answer Unix command to escape spaces you can strip blank space then make use of eval, like this:
yourPathEscaped=$(printf %q "$yourPathWithBlankSpace")
eval cd $yourPathEscaped
You can use any of:
cd ~/"My Code"
cd ~/M"y Code"
cd ~/My" Code"
You cannot use:
cd ~"/My Code"
The first works because the shell expands ~/ into $HOME/, and then tacks on My Code without the double quotes. The second fails because there isn't a user called '"' (double quote) for ~" to map to.
cd ~/My\ Code
seems to work for me... If dropping the quotes but keeping the slash doesn't work, can you post some sample code?
This will do it:
cd ~/My\ Code
I've had to use that to work with files stored in the iCloud Drive. You won't want to use double quotes (") as then it must be an absolute path. In other words, you can't combine double quotes with tilde (~).
By way of example I had to use this for a recent project:
cd ~/Library/Mobile\ Documents/com~apple~CloudDocs/Documents/Documents\ -\ My\ iMac/Project
I hope that helps.
A single backslash works for me:
ry4an#ry4an-mini:~$ mkdir "My Code"
ry4an#ry4an-mini:~$ vi todir.sh
ry4an#ry4an-mini:~$ . todir.sh
ry4an#ry4an-mini:My Code$ cat ../todir.sh
#!/bin/sh
cd ~/My\ Code
Are you sure the problem isn't that your shell script is changing directory in its subshell, but then you're back in the main shell (and original dir) when done? I avoided that by using . to run the script in the current shell, though most folks would just use an alias for this. The spaces could be a red herring.
When working under Linux the syntax below is right:
cd ~/My\ Code
However when you're executing your file, use the syntax below:
$ . cdcode
(just '.' and not './')
use double quotes
go ()
{
cd "$*"
}
The very simple way of doing this is-
$ cd My\ Folder
In bash, run DIR command and in the results you would see that the folder or path names having space between them has been written in the results like this -
$dir
My\ Folder
New\ Folder
Use single quotes, like:
myPath=~/'my dir'
cd $myPath
Avoid ~ in scripts; use $HOME instead.
I had a similar problem now were I was using a bash script to dump some data. I ended up creating a symbolic link in the script folder with out any spaces in it. I then pointed my script to the symbolic link and that works fine.
To create your link.
ln -s [TARGET DIRECTORY OR FILE] ./[SHORTCUT]
Mau or may not be of use.
I read all these, and they didn't seem to work on macOS Monterey. I then changed the header from #!/bin/sh to #!/bin/zshand that seemed to do the trick.

Resources