I'm wanting to rename
123/1/ -> 123/v1/
foo/1/ -> foo/v1/
bar/1/ -> bar/v1/
345/1/ -> 345/v1/
I've searched and found a few related solutions, but not quite sure what is best in this instance. eg,
find . -wholename "*/1" -exec echo '{}' \;
successfully prints out all the paths relative to .
, but {}
expands to ./foo/1/
, so I can't move from {}
to {}/v1
for instance. I also tried
find . -wholename "*/1" -exec mv '{}' $(echo '{}' | sed 's/1/v1/') \;
with the idea that I would be invoking mv./foo/1./foo/v1
, but apparently it tries to move .foo/1/
to a subdirectory of itself.
Anyhow, just looking for the simplest way to do this bulk renaming. To be clear, I'm trying to move the literal subdirectory 1
to v1
, not also 2
to v2
.
Something like this, untested, is IMHO the simplest way to do it using bash builtins and mandatory POSIX utils as long as your paths don't contain newlines:
while IFS= read -r old; do
new="${old##*/}v1"
echo mv -- "$old" $new"
done < <(find . -type d -name 1)
Remove echo
once you're happy with the output from initial testing.
Like this, using perl rename (which may be different than the rename
already existing on your system, use rename --version
to check):
rename -n 's|([^/]+/)(1)|$1v$2|' */1/
remove -n
(dry-run) when the outputs is ok for you.
(note that you can use globstar
on bash or something similar on other shells to recurse into deeper sub-directories)
This was tagged with fish. A solution using fish shell:
for file in **/1/; mv $file (dirname $file)/v1; end
Try
find . -depth -type d -name 1 -execdir mv 1 v1 \;
-execdir
option to find
is not POSIX, but it is widely supported by find
implementations. find -exec
? for useful information about the -execdir
option.-depth
option is necessary both to support paths like foo/1/1/1
and to avoid warning messages when find
can't traverse the newly-renamed 1
directories. I would do it in straight Bash.
Given:
$ tree .
.
├── 123
│ └── 1
├── 345
│ └── 1
│ └── 1 # this is a file named '1'
├── bar
│ └── 1
└── foo
└── 1
└── file
8 directories, 2 files
You can do:
#!/bin/bash
shopt -s globstar
new_1="v1"
for src in **/*/1; do # will RECURSIVELY find any directory '1'
# if just next level (as in example)
# you can just do */1
[ -d "$src" ] || continue
tgt="${src%%/1}/$new_1"
echo "./$src/ => ./$tgt/"
mv "./$src" "./$tgt/"
done
Result:
$ tree .
.
├── 123
│ └── v1
├── 345
│ └── v1
│ └── 1
├── bar
│ └── v1
└── foo
└── v1
└── file
8 directories, 2 files
If you want to insert parent directories, add one statement to create them:
shopt -s globstar
new_1="a parent/v1" # the replacement path has a parent
for src in **/*/1; do
[ -d "$src" ] || continue
tgt="${src%%/1}/$new_1"
[[ "/" == *"$new_1"* ]] || mkdir -p "${tgt%/*}" # create parents if any
echo "./$src/ => ./$tgt/"
mv "./$src" "./$tgt/"
done
Result:
$ tree .
.
├── 123
│ └── a parent
│ └── v1
├── 345
│ └── a parent
│ └── v1
│ └── 1
├── bar
│ └── a parent
│ └── v1
└── foo
└── a parent
└── v1
└── file
12 directories, 2 files
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.