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)
In bash 4+
#!/bin/bash
shopt -s globstar
for file in **/*; do
filename="${file##*/}"
if [[ -f $file && $filename == *" "* ]]; then
onespace=$(echo $filename)
dir="${file%/*}"
[[ ! -f "$dir/${onespace// /-}" ]] && mv "$file" "$dir/${onespace// /-}" || echo "$dir/${onespace// /-} already exists, so not moving $file" 1>&2
fi
done
Older bash
#!/bin/bash
find . -type f -print0 | while read -r -d '' file; do
filename="${file##*/}"
if [[ -f $file && $filename == *" "* ]]; then
onespace=$(echo $filename)
dir="${file%/*}"
[[ ! -f "$dir/${onespace// /-}" ]] && mv "$file" "$dir/${onespace// /-}" || echo "$dir/${onespace// /-} 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)
${file##*/}
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
${file%/*}
Remove everything after and including the last /
, e.g. /foo/bar/test.txt
prints /foo/bar
mv "$file" ${onespace// /-}
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