How to access files/directories with spaces in the name? [duplicate]
Through terminal I can’t access files or directories with a spaces in their names. The cd command says no such file or directory . Is there any way to do it or should I rename all files with spaces?
2 Answers 2
To access a directory having space in between the name use \ to access it. You can also use Tab button to auto completion of name.
guru@guru-Aspire-5738:~$ cd /media/Data/My\ Data/ guru@guru-Aspire-5738:/media/Data/My Data$.
To to use files with spaces you can either use the escape character or youse the double quotes.
\ is called escape character, used to not expansion of space, so now bash read the space as part of file name.
Now to rename files, it’s so easy to rename all files with spaces and replace space with underscore:
for file in * ; do mv "$f" "$" ; done
look at answer here there is a script to rename all files and dirs recursively.
The script is:(All rights go to its owner)
#!/bin/bash # set -o xtrace # uncomment for debugging declare weirdchars=" &\'" function normalise_and_rename() < declare -a list=("$") for fileordir in "$"; do newname="$]/_>" [[ ! -a "$newname" ]] && \ mv "$fileordir" "$newname" || \ echo "Skipping existing file, $newname." done > declare -a dirs files while IFS= read -r -d '' dir; do dirs+=("$dir") done < <(find -type d -print0 | sort -z) normalise_and_rename dirs[@] while IFS= read -r -d '' file; do files+=("$file") done < <(find -type f -print0 | sort -z) normalise_and_rename files[@]
How can I search for files in directories that contain spaces in names, using "find"?
The problem is not really with find but with the for loops since "spaces" are taken as delimiter between items.
@skamazin I have a .txt file in some directory. I want the script to search for files with the same name as that .txt file and copy them to the directory with the .txt file. And i need recursive search.
@SerjAntiquity "I want the script to search for files with the same name as that .txt file and copy them to the directory with the .txt file." If you copy a file with the same name (incl. .txt ext.) you will overwrite it. Is that expected behavior?
6 Answers 6
This will grab all the files that have spaces in them
$ls more space nospace stillnospace this is space $find -type f -name "* *" ./this is space ./more space
The filter only for regular file types is missing. The directory-type files will not be filtered in you example.
I don't know how to achieve you goal. But given your actual solution, the problem is not really with find but with the for loops since "spaces" are taken as delimiter between items.
find has a useful option for those cases:
from man find :
-print0
True; print the full file name on the standard output, followed by a null character (instead of the newline character that -print uses). This allows file names that contain newlines or other types of white space to be correctly interpreted by programs that process the find output. This option corresponds to the -0 option of xargs.
As the man saids, this will match with the -0 option of xargs . Several other standard tools have the equivalent option. You probably have to rewrite your complex pipeline around those tools in order to process cleanly file names containing spaces.
In addition, see bash "for in" looping on null delimited string variable to learn how to use for loop with 0-terminated arguments.
Bash - finding files with spaces and rename with sed [duplicate]
I have been trying to write a script to rename all files that contain a space and replace the space with a dash. Example: "Hey Bob.txt" to "Hey-Bob.txt" When I used a for-loop, it just split up the file name at the space, so "Hey Bob.txt" gave separate argument like "Hey" and "Bob.txt". I tried the following script but it keeps hanging on me. #!/bin/bash
find / -name '* *' -exec mv <> $(echo <> | sed 's/ /-g')\;
almost certainly a quoting problem, but I'm not sure if quoting <> is needed or will help. Worth trying, right? Else, go back to your loop solution and dbl-quote all references to variables. Good luck.
3 Answers 3
find $ -name '* *' -exec bash -c 'eval $(echo mv -v \"<>\" $(echo <> | sed "s/ /-/g"))' \;
EDIT: BroSlow pointed out need to consider directory structure:
find $ -name '* *' -exec bash -c 'DIR=$(dirname "<>" | sed "s/ /-/g" ); BASE=$(basename "<>"); echo mv -v \"$DIR/$BASE\" \"$DIR/$(echo $BASE | sed "s/ /-/g")\"' \; > rename-script.sh ; sh rename-script.sh
I thought about that, but then thought: "What if OP wants to rename 'Hey Bob' directories?" or even 'Hey Bob' symbolic links 🙂
Maybe what he wanted, but it's going to completely change directory trees and you still need to make nonexistent directories before you mv files there in the one liner somehow. So e.g. "/home/foo/some space dir/some file" will fail even if the mv get's processed correctly in your above example, because it will try to mv it to "/home/foo/some-space-sir/some-file"
find . -name "* *" -type f |while read file do new=$ mv "$" $new done
This is not very robust if there are other special characters in the file name, and obviously won't work at all if there are names with newlines.
Not one line, but avoids sed and should work just as well if you're going to be using it for a script anyway. (replace the mv with an echo if you want to test)
#!/bin/bash shopt -s globstar for file in **/*; do filename="$" if [[ -f $file && $filename == *" "* ]]; then onespace=$(echo $filename) dir="$" [[ ! -f "$dir/$" ]] && mv "$file" "$dir/$" || echo "$dir/$ already exists, so not moving $file" 1>&2 fi done
#!/bin/bash find . -type f -print0 | while read -r -d '' file; do filename="$" if [[ -f $file && $filename == *" "* ]]; then onespace=$(echo $filename) dir="$" [[ ! -f "$dir/$" ]] && mv "$file" "$dir/$" || echo "$dir/$ already exists, so not moving $file" 1>&2 fi done
Explanation of algorithm
- **/* This recursively lists all files in the current directory ( ** technically does it but /* is added at the end so it doesn't list the directory itself)
- $ Will search for the longest pattern of */ in file and remove it from the string. e.g. /foo/bar/test.txt gets printed as test.txt
- $(echo $filename) Without quoting echo will truncate spaces to one, making them easier to replace with one - for any number of spaces
- $ Remove everything after and including the last / , e.g. /foo/bar/test.txt prints /foo/bar
- mv "$file" $ replace every space in our filename with - (we check if the hyphened version exists before hand and if it does echo that it failed to stderr, note && is processed before || in bash)
- find . -type f -print0 | while read -r -d '' file This is used to avoid break up strings with spaces in them by setting a delimiter and not processing \
Sample Output
$ tree . ├── bar │ ├── some dir │ │ ├── some-name-without-space1.pdf │ │ ├── some name with space1.pdf │ ├── some-name-without-space1.pdf │ ├── some name with space1.pdf │ └── some-name-with-space1.pdf └── space.sh $ ./space.sh bar/some-name-with-space1.pdf already exists, so not moving bar/some name with space1.pdf $ tree . ├── bar │ ├── some dir │ │ ├── some-name-without-space1.pdf │ │ ├── some-name-with-space1.pdf │ ├── some-name-without-space1.pdf │ ├── some name with space1.pdf │ └── some-name-with-space1.pdf └── space.sh