Rename multiple files to decrement number in file name?
I have incorrectly named files which are unsynced by -1. The problem is I need to rename 1000s of them.
- DBGC180_805754
- DBGC180_805755
- DBGC180_805756
to
- DBGC180_805753
- DBGC180_805754
- DBGC180_805755
I would prefer using bash scripts or a unix command.
rename filenames recursive
add a comment |
I have incorrectly named files which are unsynced by -1. The problem is I need to rename 1000s of them.
- DBGC180_805754
- DBGC180_805755
- DBGC180_805756
to
- DBGC180_805753
- DBGC180_805754
- DBGC180_805755
I would prefer using bash scripts or a unix command.
rename filenames recursive
If you were on Mac OS X this would be a perfect use case for Name Mangler.
– Wildcard
Sep 29 '16 at 6:26
1
It's not 100% clear how the input files look like. Do all files have the same prefix DBGC180? Is 805753 the smallest number? Are there numbers with more or less than 6 digits? Are there numbers which shall not be renamed, e.g. <805753?
– rudimeier
Sep 29 '16 at 10:16
add a comment |
I have incorrectly named files which are unsynced by -1. The problem is I need to rename 1000s of them.
- DBGC180_805754
- DBGC180_805755
- DBGC180_805756
to
- DBGC180_805753
- DBGC180_805754
- DBGC180_805755
I would prefer using bash scripts or a unix command.
rename filenames recursive
I have incorrectly named files which are unsynced by -1. The problem is I need to rename 1000s of them.
- DBGC180_805754
- DBGC180_805755
- DBGC180_805756
to
- DBGC180_805753
- DBGC180_805754
- DBGC180_805755
I would prefer using bash scripts or a unix command.
rename filenames recursive
rename filenames recursive
edited Sep 29 '16 at 7:24
Wildcard
22.9k1065169
22.9k1065169
asked Sep 27 '16 at 16:48
iamunixiamunix
141
141
If you were on Mac OS X this would be a perfect use case for Name Mangler.
– Wildcard
Sep 29 '16 at 6:26
1
It's not 100% clear how the input files look like. Do all files have the same prefix DBGC180? Is 805753 the smallest number? Are there numbers with more or less than 6 digits? Are there numbers which shall not be renamed, e.g. <805753?
– rudimeier
Sep 29 '16 at 10:16
add a comment |
If you were on Mac OS X this would be a perfect use case for Name Mangler.
– Wildcard
Sep 29 '16 at 6:26
1
It's not 100% clear how the input files look like. Do all files have the same prefix DBGC180? Is 805753 the smallest number? Are there numbers with more or less than 6 digits? Are there numbers which shall not be renamed, e.g. <805753?
– rudimeier
Sep 29 '16 at 10:16
If you were on Mac OS X this would be a perfect use case for Name Mangler.
– Wildcard
Sep 29 '16 at 6:26
If you were on Mac OS X this would be a perfect use case for Name Mangler.
– Wildcard
Sep 29 '16 at 6:26
1
1
It's not 100% clear how the input files look like. Do all files have the same prefix DBGC180? Is 805753 the smallest number? Are there numbers with more or less than 6 digits? Are there numbers which shall not be renamed, e.g. <805753?
– rudimeier
Sep 29 '16 at 10:16
It's not 100% clear how the input files look like. Do all files have the same prefix DBGC180? Is 805753 the smallest number? Are there numbers with more or less than 6 digits? Are there numbers which shall not be renamed, e.g. <805753?
– rudimeier
Sep 29 '16 at 10:16
add a comment |
7 Answers
7
active
oldest
votes
- Move the files to rename into a subdirectory (without changing their name).
- Rename the files from the subdirectory into the original directory.
There are two reasons I recommend step 1, even if it's possible to do without it:
- If the command is interrupted, you can resume where you left off, since it's immediately obvious which files have already been renamed and which ones haven't.
- You don't need to worry about doing the renaming in the wrong order and overwriting one of the existing files.
Untested shell snippet (relying on the fact that the number to decrement never has any leading zeros):
mkdir to_decrement
for x in DBGC180_80575[4-9] DBGC180_8057[6-9]? DBGC180_805[8-9]?? DBGC180_80[6-9]??? DBGC180_8[1-9]???? DBGC180_9?????; do
mv "$x" to_decrement/
done
cd to_decrement
for x in *; do
number="${x##*_}"
mv -i -- "$x" "../${x%_*}_$((number-1))"
done
cd ..
rmdir to_decrement
With zsh, you can make this a lot simpler, thanks to its numeric range glob, its built-in mv
which avoids running into command line length limits, and its pattern-based mass renaming function. In zsh:
autoload -U zmv
zmodload -m -F zsh/files b:zf_*
mkdir to_decrement
zf_mv DBGC180_<805754-> to_decrement/
zmv 'to_decrement/(*)_(*)' '${1}_$(($2-1))'
rmdir to_decrement
I don't understand what is the sense behind your complicated globbing patterns. Why you don't want to rename say DBGC180_805750 but DBGC180_9yyyyy is included? Moreover the chance is high that there are too many files for one command line.
– rudimeier
Sep 29 '16 at 9:29
@rudimeier My understanding of the requirements is that only files with a number ≥805754 must be renumbered, and there are files with a smaller number that must not be renumbered. Good point about the command line length, I'll add a note about this.
– Gilles
Sep 29 '16 at 9:56
@rudimeier My understanding is that 805753 does not exist, but (at least some of) 805752, 805751, etc. do
– Gilles
Sep 29 '16 at 10:06
I see, comment to the question added.
– rudimeier
Sep 29 '16 at 10:18
add a comment |
You can do this:
# {smallestfilenum..largestfilenum}
for i in {805754..999999}; do
mv "DBGC180_$i" "DBGC180_$(($i-1))";
done
Try it with a small number (say 805754..805758) to make sure it works as you expect it. Be aware that if a file already exists with the new name, it will be overwritten.
1
Most 'mv' implementations have a-n
option to prevent overwriting. Of course, if you use that, you'll then have the problem of not knowing which names were changed and which were the originals. I recommend renaming to a temporary directory, and checking the results before moving them back:mkdir tmp && for i in {805754..999999}; do mv "DBGC180_$i" "tmp/DBGC180_$(($i-1))"; done && mv -n tmp/* . && rmdir tmp
Ormkdir tmp && mv DBGC180_* tmp/; for i in {805754..999999}; do mv -n "tmp/DBGC180_$i" "DBGC180_$(($i-1))"; done && rmdir tmp
. If thermdir
fails, you need some manual fixing.
– Toby Speight
Sep 29 '16 at 10:44
add a comment |
So, you want to rename DBGC180_805754
to DBGC180_805753
,...55
to ...54
and so forth. That's the problem I'll address.
First, put this script somewhere in your PATH
, call it waltinator
.
#!/bin/bash
#step through the parameters
while [[ -n "$1" ]] ; do
oldname="$1"
# shift the arguments left
shift;
# strip off the fixed part of the old name
oldnum=${oldname##DBGC180_}
# decrement the number (this is what was wanted, right?)
newnum=$(( $oldnum - 1 ))
# build the new, improved filename
newname="DBGC180_$newnum"
if [[ -f "$newname" ]] ; then
printf "Cannot rename $oldname to $newname, $newname exists.n" >&2
exit 1
fi
mv --no-clobber "$oldname" "$newname"
done
exit 0
For the next step, assume that the script is in $HOME/bin/waltinator
, and you have does chmod +x $HOME/bin/waltinator
.
find . -type f -name 'BDGC180_[0-9][0-9][0-9][0-9][0-9][0-9]` -print |
sort |
xargs $HOME/bin/waltinator
The find
finds files (in no particular order), whose names match the shell glob pattern "BDGC180_
followed by 6 digits ([0-9]
). Since we want a sorted list (it would be a failure to rename ...97
to ...96
before renaming ...96
) we run the output of find
through sort
. Then we use xargs
to take the (sorted) list of filenames, and build a command to pass the (sorted) list of filenames to $HOME/bin/waltinator
. Read man xargs
if you need to shorten the arg list.
For that matter, read:
for page in bash mv find sort xargs ; do
man "$page"
done
add a comment |
If you want to rename those specific files then here is the solution (static).
First rename and move those files into sub directory.
From there move those files to current directory
#!/bin/bash
# rename.sh
#make a subdirectory
mkdir -p subDir
#move all files to subdirectory with rename
for i in {5754..6754}; do
mv "DBGC180_80$i" "./subDir/DBGC180_80$(($i-1))";
done
#move all files from subdirectory to current directory
for j in {5754..6754}; do
mv "./subDir/DBGC180_80$(($j-1))" "./DBGC180_80$(($j-1))"
done
#remove subdirectory
rmdir subDir
This program can be modified to be generic (dynamic)
Huh? Why, in your "move from subdir to current dir" code block, do you even bother withj-1
(since you're doing it twice)? Why not just change the numbers used for iteration?
– Wildcard
Sep 29 '16 at 6:22
Of course, it can be done as you said. I kept it in a single line.
– firoj_mujawar
Oct 3 '16 at 7:49
add a comment |
Use rename
to substitute each number with itself minus 1.
$ rename -v 's/d{6}/sprintf("%06",($&-1))/e'
Notes
rename
uses Perl expressions to rename filenames.
s
specifies thatrename
will substitute some or all of the filenames that match the regular expression pattern.- Perl substitution expressions are structured as such.
s/PATTERN/REPLACEMENT/MODIFIER
d{6}
is the pattern thatrename
will search for and substitute. This is 6 decimal digits.
$
is the variable storing the substring that matchedd{6}
(in this case the "substring" is an int).
sprintf("%06",($&-1))
retrieves the value stored in$
, decrements it, then returns this value as the replacement. The%06
is there to handle leading zeroes.
e
specified thatrename
evaluates the replacement as if it were a Perl statement, and uses its return value as the replacement text.
-v
makesrename
echo what it is doing.
If you want to be extra safe use the flag -n
so that rename
only tells you what it would do instead of doing it.
This appears to only work for decrementing so handle this with care.
New contributor
add a comment |
Wow, this was trickier than I expected.
As Gilles pointed out, considering the number of files to be handled, you should rename them in a way that won't give you problems if the command is interrupted. The command below does that.
I wrote this command to be fairly robust against failures. Note that we explicitly exclude files where the number has a leading 0; if you have files like that, post a comment and I'll include a command to deal with them.
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]' -exec sh -c 'for f; do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented"; done' find-sh-decrement {} + && find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented' -exec sh -c 'for f; do mv -i "$f" "${f%.decremented}"; done' find-sh-remove-prefix {} +
With line wrappings (can still be copied and pasted):
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]'
-exec sh -c 'for f;
do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented";
done' find-sh-decrement {} + &&
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented'
-exec sh -c 'for f;
do mv -i "$f" "${f%.decremented}";
done' find-sh-remove-prefix {} +
Explanation of the parts (this could use some formatting cleanup):
##### Recursively find regular files in the current directory...
find . -type f
##### whose name matches this exact pattern...
-name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]'
##### and run the following shell script...
-exec sh -c
##### (shell script: ) for every file given as an argument...
'for f;
##### rename the file, prompting for confirmation for any overwrites...
do mv -i
##### from the original file name...
"$f"
##### to the file name decremented by 1, with '.decremented' afterward...
"${f%_*}_$((${f##*_}-1)).decremented";
##### (End of shell script)
done'
##### on as many found files as possible at once,
##### using the name "find-sh-decrement" for error reporting.
find-sh-decrement {} +
##### If that completes successfully...
&&
##### Pass through again and remove the ".decremented" prefix.
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented' -exec sh -c 'for f; do mv -i "$f" "${f%.decremented}"; done' find-sh-remove-prefix {} +
Test results:
$ ls
DBGC180_805754 DBGC180_805755 DBGC180_805756
$ cat DBGC180_805754
This file started as DBGC180_805754
$ cat DBGC180_805755
This file started as DBGC180_805755
$ cat DBGC180_805756
This file started as DBGC180_805756
$ find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]' -exec sh -c 'for f; do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented"; done' find-sh-decrement {} + && find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented' -exec sh -c 'for f; do mv -i "$f" "${f%.decremented}"; done' find-sh-remove-prefix {} +
$ ls
DBGC180_805753 DBGC180_805754 DBGC180_805755
$ cat DBGC180_805753
This file started as DBGC180_805754
$ cat DBGC180_805754
This file started as DBGC180_805755
$ cat DBGC180_805755
This file started as DBGC180_805756
$
For extra safety, run the first find
command and inspect the results for yourself before you run the second command to remove the .decremented
suffix.
Run this:
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]'
-exec sh -c 'for f;
do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented";
done' find-sh-decrement {} +
Then inspect results, and then run this:
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented'
-exec sh -c 'for f;
do mv -i "$f" "${f%.decremented}";
done' find-sh-remove-prefix {} +
Why the downvote? This does exactly what was requested, and is quite clean in my opinion.
– Wildcard
Oct 3 '16 at 14:34
add a comment |
Use awk
to create a fully expanded rename script:
find . -name "DBGC180_*" |sort |awk -F "_" '{print "mv -i "$0" "$1"_"$2-1}' >/tmp/rename.sh
You can review the script before executing. This is the unique feature of this solution. Then execute it:
sh -e -x /tmp/rename.sh
Notes
- you may improve the find pattern, the question is not 100% clear about what files has to be renamed.
sort
is important to not overwrite existing files
mv
option-i
makes it extra-safe to never overwrite files
sh
option-e
is to abort the script in case of error
sh
option-x
prints a trace to see what was done so far in case the script is interrupted (to make recovery possible). You could also usemv -v
instead if supported.
Down voters! Please comment whats wrong here.
– rudimeier
Sep 29 '16 at 11:12
Your added explanations are good, and the script may work fine for the exact use case of the Original Poster. However, it is definitely not robust. (My own definition of robust: Does not produce unexpected output in the face of unexpected input.) There are a great many caveats if the script would be modified and used more generally, and you don't note these: (1) It won't handle whitespace correctly, or even underscores, if they appear within directory names (i.e. not truly recursive); (cont'd)
– Wildcard
Sep 29 '16 at 19:51
(cont'd) (2) It won't handle file extensions (see what happens if you give it the fileDBGC180_5555.txt
, for instance); (3) If the script is interrupted partway through there is no way to tell which files have been renamed and which haven't been.
– Wildcard
Sep 29 '16 at 19:51
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "106"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f312748%2frename-multiple-files-to-decrement-number-in-file-name%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
7 Answers
7
active
oldest
votes
7 Answers
7
active
oldest
votes
active
oldest
votes
active
oldest
votes
- Move the files to rename into a subdirectory (without changing their name).
- Rename the files from the subdirectory into the original directory.
There are two reasons I recommend step 1, even if it's possible to do without it:
- If the command is interrupted, you can resume where you left off, since it's immediately obvious which files have already been renamed and which ones haven't.
- You don't need to worry about doing the renaming in the wrong order and overwriting one of the existing files.
Untested shell snippet (relying on the fact that the number to decrement never has any leading zeros):
mkdir to_decrement
for x in DBGC180_80575[4-9] DBGC180_8057[6-9]? DBGC180_805[8-9]?? DBGC180_80[6-9]??? DBGC180_8[1-9]???? DBGC180_9?????; do
mv "$x" to_decrement/
done
cd to_decrement
for x in *; do
number="${x##*_}"
mv -i -- "$x" "../${x%_*}_$((number-1))"
done
cd ..
rmdir to_decrement
With zsh, you can make this a lot simpler, thanks to its numeric range glob, its built-in mv
which avoids running into command line length limits, and its pattern-based mass renaming function. In zsh:
autoload -U zmv
zmodload -m -F zsh/files b:zf_*
mkdir to_decrement
zf_mv DBGC180_<805754-> to_decrement/
zmv 'to_decrement/(*)_(*)' '${1}_$(($2-1))'
rmdir to_decrement
I don't understand what is the sense behind your complicated globbing patterns. Why you don't want to rename say DBGC180_805750 but DBGC180_9yyyyy is included? Moreover the chance is high that there are too many files for one command line.
– rudimeier
Sep 29 '16 at 9:29
@rudimeier My understanding of the requirements is that only files with a number ≥805754 must be renumbered, and there are files with a smaller number that must not be renumbered. Good point about the command line length, I'll add a note about this.
– Gilles
Sep 29 '16 at 9:56
@rudimeier My understanding is that 805753 does not exist, but (at least some of) 805752, 805751, etc. do
– Gilles
Sep 29 '16 at 10:06
I see, comment to the question added.
– rudimeier
Sep 29 '16 at 10:18
add a comment |
- Move the files to rename into a subdirectory (without changing their name).
- Rename the files from the subdirectory into the original directory.
There are two reasons I recommend step 1, even if it's possible to do without it:
- If the command is interrupted, you can resume where you left off, since it's immediately obvious which files have already been renamed and which ones haven't.
- You don't need to worry about doing the renaming in the wrong order and overwriting one of the existing files.
Untested shell snippet (relying on the fact that the number to decrement never has any leading zeros):
mkdir to_decrement
for x in DBGC180_80575[4-9] DBGC180_8057[6-9]? DBGC180_805[8-9]?? DBGC180_80[6-9]??? DBGC180_8[1-9]???? DBGC180_9?????; do
mv "$x" to_decrement/
done
cd to_decrement
for x in *; do
number="${x##*_}"
mv -i -- "$x" "../${x%_*}_$((number-1))"
done
cd ..
rmdir to_decrement
With zsh, you can make this a lot simpler, thanks to its numeric range glob, its built-in mv
which avoids running into command line length limits, and its pattern-based mass renaming function. In zsh:
autoload -U zmv
zmodload -m -F zsh/files b:zf_*
mkdir to_decrement
zf_mv DBGC180_<805754-> to_decrement/
zmv 'to_decrement/(*)_(*)' '${1}_$(($2-1))'
rmdir to_decrement
I don't understand what is the sense behind your complicated globbing patterns. Why you don't want to rename say DBGC180_805750 but DBGC180_9yyyyy is included? Moreover the chance is high that there are too many files for one command line.
– rudimeier
Sep 29 '16 at 9:29
@rudimeier My understanding of the requirements is that only files with a number ≥805754 must be renumbered, and there are files with a smaller number that must not be renumbered. Good point about the command line length, I'll add a note about this.
– Gilles
Sep 29 '16 at 9:56
@rudimeier My understanding is that 805753 does not exist, but (at least some of) 805752, 805751, etc. do
– Gilles
Sep 29 '16 at 10:06
I see, comment to the question added.
– rudimeier
Sep 29 '16 at 10:18
add a comment |
- Move the files to rename into a subdirectory (without changing their name).
- Rename the files from the subdirectory into the original directory.
There are two reasons I recommend step 1, even if it's possible to do without it:
- If the command is interrupted, you can resume where you left off, since it's immediately obvious which files have already been renamed and which ones haven't.
- You don't need to worry about doing the renaming in the wrong order and overwriting one of the existing files.
Untested shell snippet (relying on the fact that the number to decrement never has any leading zeros):
mkdir to_decrement
for x in DBGC180_80575[4-9] DBGC180_8057[6-9]? DBGC180_805[8-9]?? DBGC180_80[6-9]??? DBGC180_8[1-9]???? DBGC180_9?????; do
mv "$x" to_decrement/
done
cd to_decrement
for x in *; do
number="${x##*_}"
mv -i -- "$x" "../${x%_*}_$((number-1))"
done
cd ..
rmdir to_decrement
With zsh, you can make this a lot simpler, thanks to its numeric range glob, its built-in mv
which avoids running into command line length limits, and its pattern-based mass renaming function. In zsh:
autoload -U zmv
zmodload -m -F zsh/files b:zf_*
mkdir to_decrement
zf_mv DBGC180_<805754-> to_decrement/
zmv 'to_decrement/(*)_(*)' '${1}_$(($2-1))'
rmdir to_decrement
- Move the files to rename into a subdirectory (without changing their name).
- Rename the files from the subdirectory into the original directory.
There are two reasons I recommend step 1, even if it's possible to do without it:
- If the command is interrupted, you can resume where you left off, since it's immediately obvious which files have already been renamed and which ones haven't.
- You don't need to worry about doing the renaming in the wrong order and overwriting one of the existing files.
Untested shell snippet (relying on the fact that the number to decrement never has any leading zeros):
mkdir to_decrement
for x in DBGC180_80575[4-9] DBGC180_8057[6-9]? DBGC180_805[8-9]?? DBGC180_80[6-9]??? DBGC180_8[1-9]???? DBGC180_9?????; do
mv "$x" to_decrement/
done
cd to_decrement
for x in *; do
number="${x##*_}"
mv -i -- "$x" "../${x%_*}_$((number-1))"
done
cd ..
rmdir to_decrement
With zsh, you can make this a lot simpler, thanks to its numeric range glob, its built-in mv
which avoids running into command line length limits, and its pattern-based mass renaming function. In zsh:
autoload -U zmv
zmodload -m -F zsh/files b:zf_*
mkdir to_decrement
zf_mv DBGC180_<805754-> to_decrement/
zmv 'to_decrement/(*)_(*)' '${1}_$(($2-1))'
rmdir to_decrement
edited Sep 29 '16 at 10:05
answered Sep 29 '16 at 1:31
GillesGilles
540k12810941608
540k12810941608
I don't understand what is the sense behind your complicated globbing patterns. Why you don't want to rename say DBGC180_805750 but DBGC180_9yyyyy is included? Moreover the chance is high that there are too many files for one command line.
– rudimeier
Sep 29 '16 at 9:29
@rudimeier My understanding of the requirements is that only files with a number ≥805754 must be renumbered, and there are files with a smaller number that must not be renumbered. Good point about the command line length, I'll add a note about this.
– Gilles
Sep 29 '16 at 9:56
@rudimeier My understanding is that 805753 does not exist, but (at least some of) 805752, 805751, etc. do
– Gilles
Sep 29 '16 at 10:06
I see, comment to the question added.
– rudimeier
Sep 29 '16 at 10:18
add a comment |
I don't understand what is the sense behind your complicated globbing patterns. Why you don't want to rename say DBGC180_805750 but DBGC180_9yyyyy is included? Moreover the chance is high that there are too many files for one command line.
– rudimeier
Sep 29 '16 at 9:29
@rudimeier My understanding of the requirements is that only files with a number ≥805754 must be renumbered, and there are files with a smaller number that must not be renumbered. Good point about the command line length, I'll add a note about this.
– Gilles
Sep 29 '16 at 9:56
@rudimeier My understanding is that 805753 does not exist, but (at least some of) 805752, 805751, etc. do
– Gilles
Sep 29 '16 at 10:06
I see, comment to the question added.
– rudimeier
Sep 29 '16 at 10:18
I don't understand what is the sense behind your complicated globbing patterns. Why you don't want to rename say DBGC180_805750 but DBGC180_9yyyyy is included? Moreover the chance is high that there are too many files for one command line.
– rudimeier
Sep 29 '16 at 9:29
I don't understand what is the sense behind your complicated globbing patterns. Why you don't want to rename say DBGC180_805750 but DBGC180_9yyyyy is included? Moreover the chance is high that there are too many files for one command line.
– rudimeier
Sep 29 '16 at 9:29
@rudimeier My understanding of the requirements is that only files with a number ≥805754 must be renumbered, and there are files with a smaller number that must not be renumbered. Good point about the command line length, I'll add a note about this.
– Gilles
Sep 29 '16 at 9:56
@rudimeier My understanding of the requirements is that only files with a number ≥805754 must be renumbered, and there are files with a smaller number that must not be renumbered. Good point about the command line length, I'll add a note about this.
– Gilles
Sep 29 '16 at 9:56
@rudimeier My understanding is that 805753 does not exist, but (at least some of) 805752, 805751, etc. do
– Gilles
Sep 29 '16 at 10:06
@rudimeier My understanding is that 805753 does not exist, but (at least some of) 805752, 805751, etc. do
– Gilles
Sep 29 '16 at 10:06
I see, comment to the question added.
– rudimeier
Sep 29 '16 at 10:18
I see, comment to the question added.
– rudimeier
Sep 29 '16 at 10:18
add a comment |
You can do this:
# {smallestfilenum..largestfilenum}
for i in {805754..999999}; do
mv "DBGC180_$i" "DBGC180_$(($i-1))";
done
Try it with a small number (say 805754..805758) to make sure it works as you expect it. Be aware that if a file already exists with the new name, it will be overwritten.
1
Most 'mv' implementations have a-n
option to prevent overwriting. Of course, if you use that, you'll then have the problem of not knowing which names were changed and which were the originals. I recommend renaming to a temporary directory, and checking the results before moving them back:mkdir tmp && for i in {805754..999999}; do mv "DBGC180_$i" "tmp/DBGC180_$(($i-1))"; done && mv -n tmp/* . && rmdir tmp
Ormkdir tmp && mv DBGC180_* tmp/; for i in {805754..999999}; do mv -n "tmp/DBGC180_$i" "DBGC180_$(($i-1))"; done && rmdir tmp
. If thermdir
fails, you need some manual fixing.
– Toby Speight
Sep 29 '16 at 10:44
add a comment |
You can do this:
# {smallestfilenum..largestfilenum}
for i in {805754..999999}; do
mv "DBGC180_$i" "DBGC180_$(($i-1))";
done
Try it with a small number (say 805754..805758) to make sure it works as you expect it. Be aware that if a file already exists with the new name, it will be overwritten.
1
Most 'mv' implementations have a-n
option to prevent overwriting. Of course, if you use that, you'll then have the problem of not knowing which names were changed and which were the originals. I recommend renaming to a temporary directory, and checking the results before moving them back:mkdir tmp && for i in {805754..999999}; do mv "DBGC180_$i" "tmp/DBGC180_$(($i-1))"; done && mv -n tmp/* . && rmdir tmp
Ormkdir tmp && mv DBGC180_* tmp/; for i in {805754..999999}; do mv -n "tmp/DBGC180_$i" "DBGC180_$(($i-1))"; done && rmdir tmp
. If thermdir
fails, you need some manual fixing.
– Toby Speight
Sep 29 '16 at 10:44
add a comment |
You can do this:
# {smallestfilenum..largestfilenum}
for i in {805754..999999}; do
mv "DBGC180_$i" "DBGC180_$(($i-1))";
done
Try it with a small number (say 805754..805758) to make sure it works as you expect it. Be aware that if a file already exists with the new name, it will be overwritten.
You can do this:
# {smallestfilenum..largestfilenum}
for i in {805754..999999}; do
mv "DBGC180_$i" "DBGC180_$(($i-1))";
done
Try it with a small number (say 805754..805758) to make sure it works as you expect it. Be aware that if a file already exists with the new name, it will be overwritten.
edited Sep 27 '16 at 18:04
answered Sep 27 '16 at 17:52
Alberto RiveraAlberto Rivera
1798
1798
1
Most 'mv' implementations have a-n
option to prevent overwriting. Of course, if you use that, you'll then have the problem of not knowing which names were changed and which were the originals. I recommend renaming to a temporary directory, and checking the results before moving them back:mkdir tmp && for i in {805754..999999}; do mv "DBGC180_$i" "tmp/DBGC180_$(($i-1))"; done && mv -n tmp/* . && rmdir tmp
Ormkdir tmp && mv DBGC180_* tmp/; for i in {805754..999999}; do mv -n "tmp/DBGC180_$i" "DBGC180_$(($i-1))"; done && rmdir tmp
. If thermdir
fails, you need some manual fixing.
– Toby Speight
Sep 29 '16 at 10:44
add a comment |
1
Most 'mv' implementations have a-n
option to prevent overwriting. Of course, if you use that, you'll then have the problem of not knowing which names were changed and which were the originals. I recommend renaming to a temporary directory, and checking the results before moving them back:mkdir tmp && for i in {805754..999999}; do mv "DBGC180_$i" "tmp/DBGC180_$(($i-1))"; done && mv -n tmp/* . && rmdir tmp
Ormkdir tmp && mv DBGC180_* tmp/; for i in {805754..999999}; do mv -n "tmp/DBGC180_$i" "DBGC180_$(($i-1))"; done && rmdir tmp
. If thermdir
fails, you need some manual fixing.
– Toby Speight
Sep 29 '16 at 10:44
1
1
Most 'mv' implementations have a
-n
option to prevent overwriting. Of course, if you use that, you'll then have the problem of not knowing which names were changed and which were the originals. I recommend renaming to a temporary directory, and checking the results before moving them back: mkdir tmp && for i in {805754..999999}; do mv "DBGC180_$i" "tmp/DBGC180_$(($i-1))"; done && mv -n tmp/* . && rmdir tmp
Or mkdir tmp && mv DBGC180_* tmp/; for i in {805754..999999}; do mv -n "tmp/DBGC180_$i" "DBGC180_$(($i-1))"; done && rmdir tmp
. If the rmdir
fails, you need some manual fixing.– Toby Speight
Sep 29 '16 at 10:44
Most 'mv' implementations have a
-n
option to prevent overwriting. Of course, if you use that, you'll then have the problem of not knowing which names were changed and which were the originals. I recommend renaming to a temporary directory, and checking the results before moving them back: mkdir tmp && for i in {805754..999999}; do mv "DBGC180_$i" "tmp/DBGC180_$(($i-1))"; done && mv -n tmp/* . && rmdir tmp
Or mkdir tmp && mv DBGC180_* tmp/; for i in {805754..999999}; do mv -n "tmp/DBGC180_$i" "DBGC180_$(($i-1))"; done && rmdir tmp
. If the rmdir
fails, you need some manual fixing.– Toby Speight
Sep 29 '16 at 10:44
add a comment |
So, you want to rename DBGC180_805754
to DBGC180_805753
,...55
to ...54
and so forth. That's the problem I'll address.
First, put this script somewhere in your PATH
, call it waltinator
.
#!/bin/bash
#step through the parameters
while [[ -n "$1" ]] ; do
oldname="$1"
# shift the arguments left
shift;
# strip off the fixed part of the old name
oldnum=${oldname##DBGC180_}
# decrement the number (this is what was wanted, right?)
newnum=$(( $oldnum - 1 ))
# build the new, improved filename
newname="DBGC180_$newnum"
if [[ -f "$newname" ]] ; then
printf "Cannot rename $oldname to $newname, $newname exists.n" >&2
exit 1
fi
mv --no-clobber "$oldname" "$newname"
done
exit 0
For the next step, assume that the script is in $HOME/bin/waltinator
, and you have does chmod +x $HOME/bin/waltinator
.
find . -type f -name 'BDGC180_[0-9][0-9][0-9][0-9][0-9][0-9]` -print |
sort |
xargs $HOME/bin/waltinator
The find
finds files (in no particular order), whose names match the shell glob pattern "BDGC180_
followed by 6 digits ([0-9]
). Since we want a sorted list (it would be a failure to rename ...97
to ...96
before renaming ...96
) we run the output of find
through sort
. Then we use xargs
to take the (sorted) list of filenames, and build a command to pass the (sorted) list of filenames to $HOME/bin/waltinator
. Read man xargs
if you need to shorten the arg list.
For that matter, read:
for page in bash mv find sort xargs ; do
man "$page"
done
add a comment |
So, you want to rename DBGC180_805754
to DBGC180_805753
,...55
to ...54
and so forth. That's the problem I'll address.
First, put this script somewhere in your PATH
, call it waltinator
.
#!/bin/bash
#step through the parameters
while [[ -n "$1" ]] ; do
oldname="$1"
# shift the arguments left
shift;
# strip off the fixed part of the old name
oldnum=${oldname##DBGC180_}
# decrement the number (this is what was wanted, right?)
newnum=$(( $oldnum - 1 ))
# build the new, improved filename
newname="DBGC180_$newnum"
if [[ -f "$newname" ]] ; then
printf "Cannot rename $oldname to $newname, $newname exists.n" >&2
exit 1
fi
mv --no-clobber "$oldname" "$newname"
done
exit 0
For the next step, assume that the script is in $HOME/bin/waltinator
, and you have does chmod +x $HOME/bin/waltinator
.
find . -type f -name 'BDGC180_[0-9][0-9][0-9][0-9][0-9][0-9]` -print |
sort |
xargs $HOME/bin/waltinator
The find
finds files (in no particular order), whose names match the shell glob pattern "BDGC180_
followed by 6 digits ([0-9]
). Since we want a sorted list (it would be a failure to rename ...97
to ...96
before renaming ...96
) we run the output of find
through sort
. Then we use xargs
to take the (sorted) list of filenames, and build a command to pass the (sorted) list of filenames to $HOME/bin/waltinator
. Read man xargs
if you need to shorten the arg list.
For that matter, read:
for page in bash mv find sort xargs ; do
man "$page"
done
add a comment |
So, you want to rename DBGC180_805754
to DBGC180_805753
,...55
to ...54
and so forth. That's the problem I'll address.
First, put this script somewhere in your PATH
, call it waltinator
.
#!/bin/bash
#step through the parameters
while [[ -n "$1" ]] ; do
oldname="$1"
# shift the arguments left
shift;
# strip off the fixed part of the old name
oldnum=${oldname##DBGC180_}
# decrement the number (this is what was wanted, right?)
newnum=$(( $oldnum - 1 ))
# build the new, improved filename
newname="DBGC180_$newnum"
if [[ -f "$newname" ]] ; then
printf "Cannot rename $oldname to $newname, $newname exists.n" >&2
exit 1
fi
mv --no-clobber "$oldname" "$newname"
done
exit 0
For the next step, assume that the script is in $HOME/bin/waltinator
, and you have does chmod +x $HOME/bin/waltinator
.
find . -type f -name 'BDGC180_[0-9][0-9][0-9][0-9][0-9][0-9]` -print |
sort |
xargs $HOME/bin/waltinator
The find
finds files (in no particular order), whose names match the shell glob pattern "BDGC180_
followed by 6 digits ([0-9]
). Since we want a sorted list (it would be a failure to rename ...97
to ...96
before renaming ...96
) we run the output of find
through sort
. Then we use xargs
to take the (sorted) list of filenames, and build a command to pass the (sorted) list of filenames to $HOME/bin/waltinator
. Read man xargs
if you need to shorten the arg list.
For that matter, read:
for page in bash mv find sort xargs ; do
man "$page"
done
So, you want to rename DBGC180_805754
to DBGC180_805753
,...55
to ...54
and so forth. That's the problem I'll address.
First, put this script somewhere in your PATH
, call it waltinator
.
#!/bin/bash
#step through the parameters
while [[ -n "$1" ]] ; do
oldname="$1"
# shift the arguments left
shift;
# strip off the fixed part of the old name
oldnum=${oldname##DBGC180_}
# decrement the number (this is what was wanted, right?)
newnum=$(( $oldnum - 1 ))
# build the new, improved filename
newname="DBGC180_$newnum"
if [[ -f "$newname" ]] ; then
printf "Cannot rename $oldname to $newname, $newname exists.n" >&2
exit 1
fi
mv --no-clobber "$oldname" "$newname"
done
exit 0
For the next step, assume that the script is in $HOME/bin/waltinator
, and you have does chmod +x $HOME/bin/waltinator
.
find . -type f -name 'BDGC180_[0-9][0-9][0-9][0-9][0-9][0-9]` -print |
sort |
xargs $HOME/bin/waltinator
The find
finds files (in no particular order), whose names match the shell glob pattern "BDGC180_
followed by 6 digits ([0-9]
). Since we want a sorted list (it would be a failure to rename ...97
to ...96
before renaming ...96
) we run the output of find
through sort
. Then we use xargs
to take the (sorted) list of filenames, and build a command to pass the (sorted) list of filenames to $HOME/bin/waltinator
. Read man xargs
if you need to shorten the arg list.
For that matter, read:
for page in bash mv find sort xargs ; do
man "$page"
done
answered Sep 27 '16 at 17:44
waltinatorwaltinator
75048
75048
add a comment |
add a comment |
If you want to rename those specific files then here is the solution (static).
First rename and move those files into sub directory.
From there move those files to current directory
#!/bin/bash
# rename.sh
#make a subdirectory
mkdir -p subDir
#move all files to subdirectory with rename
for i in {5754..6754}; do
mv "DBGC180_80$i" "./subDir/DBGC180_80$(($i-1))";
done
#move all files from subdirectory to current directory
for j in {5754..6754}; do
mv "./subDir/DBGC180_80$(($j-1))" "./DBGC180_80$(($j-1))"
done
#remove subdirectory
rmdir subDir
This program can be modified to be generic (dynamic)
Huh? Why, in your "move from subdir to current dir" code block, do you even bother withj-1
(since you're doing it twice)? Why not just change the numbers used for iteration?
– Wildcard
Sep 29 '16 at 6:22
Of course, it can be done as you said. I kept it in a single line.
– firoj_mujawar
Oct 3 '16 at 7:49
add a comment |
If you want to rename those specific files then here is the solution (static).
First rename and move those files into sub directory.
From there move those files to current directory
#!/bin/bash
# rename.sh
#make a subdirectory
mkdir -p subDir
#move all files to subdirectory with rename
for i in {5754..6754}; do
mv "DBGC180_80$i" "./subDir/DBGC180_80$(($i-1))";
done
#move all files from subdirectory to current directory
for j in {5754..6754}; do
mv "./subDir/DBGC180_80$(($j-1))" "./DBGC180_80$(($j-1))"
done
#remove subdirectory
rmdir subDir
This program can be modified to be generic (dynamic)
Huh? Why, in your "move from subdir to current dir" code block, do you even bother withj-1
(since you're doing it twice)? Why not just change the numbers used for iteration?
– Wildcard
Sep 29 '16 at 6:22
Of course, it can be done as you said. I kept it in a single line.
– firoj_mujawar
Oct 3 '16 at 7:49
add a comment |
If you want to rename those specific files then here is the solution (static).
First rename and move those files into sub directory.
From there move those files to current directory
#!/bin/bash
# rename.sh
#make a subdirectory
mkdir -p subDir
#move all files to subdirectory with rename
for i in {5754..6754}; do
mv "DBGC180_80$i" "./subDir/DBGC180_80$(($i-1))";
done
#move all files from subdirectory to current directory
for j in {5754..6754}; do
mv "./subDir/DBGC180_80$(($j-1))" "./DBGC180_80$(($j-1))"
done
#remove subdirectory
rmdir subDir
This program can be modified to be generic (dynamic)
If you want to rename those specific files then here is the solution (static).
First rename and move those files into sub directory.
From there move those files to current directory
#!/bin/bash
# rename.sh
#make a subdirectory
mkdir -p subDir
#move all files to subdirectory with rename
for i in {5754..6754}; do
mv "DBGC180_80$i" "./subDir/DBGC180_80$(($i-1))";
done
#move all files from subdirectory to current directory
for j in {5754..6754}; do
mv "./subDir/DBGC180_80$(($j-1))" "./DBGC180_80$(($j-1))"
done
#remove subdirectory
rmdir subDir
This program can be modified to be generic (dynamic)
answered Sep 29 '16 at 5:37
firoj_mujawarfiroj_mujawar
4017
4017
Huh? Why, in your "move from subdir to current dir" code block, do you even bother withj-1
(since you're doing it twice)? Why not just change the numbers used for iteration?
– Wildcard
Sep 29 '16 at 6:22
Of course, it can be done as you said. I kept it in a single line.
– firoj_mujawar
Oct 3 '16 at 7:49
add a comment |
Huh? Why, in your "move from subdir to current dir" code block, do you even bother withj-1
(since you're doing it twice)? Why not just change the numbers used for iteration?
– Wildcard
Sep 29 '16 at 6:22
Of course, it can be done as you said. I kept it in a single line.
– firoj_mujawar
Oct 3 '16 at 7:49
Huh? Why, in your "move from subdir to current dir" code block, do you even bother with
j-1
(since you're doing it twice)? Why not just change the numbers used for iteration?– Wildcard
Sep 29 '16 at 6:22
Huh? Why, in your "move from subdir to current dir" code block, do you even bother with
j-1
(since you're doing it twice)? Why not just change the numbers used for iteration?– Wildcard
Sep 29 '16 at 6:22
Of course, it can be done as you said. I kept it in a single line.
– firoj_mujawar
Oct 3 '16 at 7:49
Of course, it can be done as you said. I kept it in a single line.
– firoj_mujawar
Oct 3 '16 at 7:49
add a comment |
Use rename
to substitute each number with itself minus 1.
$ rename -v 's/d{6}/sprintf("%06",($&-1))/e'
Notes
rename
uses Perl expressions to rename filenames.
s
specifies thatrename
will substitute some or all of the filenames that match the regular expression pattern.- Perl substitution expressions are structured as such.
s/PATTERN/REPLACEMENT/MODIFIER
d{6}
is the pattern thatrename
will search for and substitute. This is 6 decimal digits.
$
is the variable storing the substring that matchedd{6}
(in this case the "substring" is an int).
sprintf("%06",($&-1))
retrieves the value stored in$
, decrements it, then returns this value as the replacement. The%06
is there to handle leading zeroes.
e
specified thatrename
evaluates the replacement as if it were a Perl statement, and uses its return value as the replacement text.
-v
makesrename
echo what it is doing.
If you want to be extra safe use the flag -n
so that rename
only tells you what it would do instead of doing it.
This appears to only work for decrementing so handle this with care.
New contributor
add a comment |
Use rename
to substitute each number with itself minus 1.
$ rename -v 's/d{6}/sprintf("%06",($&-1))/e'
Notes
rename
uses Perl expressions to rename filenames.
s
specifies thatrename
will substitute some or all of the filenames that match the regular expression pattern.- Perl substitution expressions are structured as such.
s/PATTERN/REPLACEMENT/MODIFIER
d{6}
is the pattern thatrename
will search for and substitute. This is 6 decimal digits.
$
is the variable storing the substring that matchedd{6}
(in this case the "substring" is an int).
sprintf("%06",($&-1))
retrieves the value stored in$
, decrements it, then returns this value as the replacement. The%06
is there to handle leading zeroes.
e
specified thatrename
evaluates the replacement as if it were a Perl statement, and uses its return value as the replacement text.
-v
makesrename
echo what it is doing.
If you want to be extra safe use the flag -n
so that rename
only tells you what it would do instead of doing it.
This appears to only work for decrementing so handle this with care.
New contributor
add a comment |
Use rename
to substitute each number with itself minus 1.
$ rename -v 's/d{6}/sprintf("%06",($&-1))/e'
Notes
rename
uses Perl expressions to rename filenames.
s
specifies thatrename
will substitute some or all of the filenames that match the regular expression pattern.- Perl substitution expressions are structured as such.
s/PATTERN/REPLACEMENT/MODIFIER
d{6}
is the pattern thatrename
will search for and substitute. This is 6 decimal digits.
$
is the variable storing the substring that matchedd{6}
(in this case the "substring" is an int).
sprintf("%06",($&-1))
retrieves the value stored in$
, decrements it, then returns this value as the replacement. The%06
is there to handle leading zeroes.
e
specified thatrename
evaluates the replacement as if it were a Perl statement, and uses its return value as the replacement text.
-v
makesrename
echo what it is doing.
If you want to be extra safe use the flag -n
so that rename
only tells you what it would do instead of doing it.
This appears to only work for decrementing so handle this with care.
New contributor
Use rename
to substitute each number with itself minus 1.
$ rename -v 's/d{6}/sprintf("%06",($&-1))/e'
Notes
rename
uses Perl expressions to rename filenames.
s
specifies thatrename
will substitute some or all of the filenames that match the regular expression pattern.- Perl substitution expressions are structured as such.
s/PATTERN/REPLACEMENT/MODIFIER
d{6}
is the pattern thatrename
will search for and substitute. This is 6 decimal digits.
$
is the variable storing the substring that matchedd{6}
(in this case the "substring" is an int).
sprintf("%06",($&-1))
retrieves the value stored in$
, decrements it, then returns this value as the replacement. The%06
is there to handle leading zeroes.
e
specified thatrename
evaluates the replacement as if it were a Perl statement, and uses its return value as the replacement text.
-v
makesrename
echo what it is doing.
If you want to be extra safe use the flag -n
so that rename
only tells you what it would do instead of doing it.
This appears to only work for decrementing so handle this with care.
New contributor
New contributor
answered 17 mins ago
coffee-dancoffee-dan
1
1
New contributor
New contributor
add a comment |
add a comment |
Wow, this was trickier than I expected.
As Gilles pointed out, considering the number of files to be handled, you should rename them in a way that won't give you problems if the command is interrupted. The command below does that.
I wrote this command to be fairly robust against failures. Note that we explicitly exclude files where the number has a leading 0; if you have files like that, post a comment and I'll include a command to deal with them.
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]' -exec sh -c 'for f; do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented"; done' find-sh-decrement {} + && find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented' -exec sh -c 'for f; do mv -i "$f" "${f%.decremented}"; done' find-sh-remove-prefix {} +
With line wrappings (can still be copied and pasted):
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]'
-exec sh -c 'for f;
do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented";
done' find-sh-decrement {} + &&
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented'
-exec sh -c 'for f;
do mv -i "$f" "${f%.decremented}";
done' find-sh-remove-prefix {} +
Explanation of the parts (this could use some formatting cleanup):
##### Recursively find regular files in the current directory...
find . -type f
##### whose name matches this exact pattern...
-name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]'
##### and run the following shell script...
-exec sh -c
##### (shell script: ) for every file given as an argument...
'for f;
##### rename the file, prompting for confirmation for any overwrites...
do mv -i
##### from the original file name...
"$f"
##### to the file name decremented by 1, with '.decremented' afterward...
"${f%_*}_$((${f##*_}-1)).decremented";
##### (End of shell script)
done'
##### on as many found files as possible at once,
##### using the name "find-sh-decrement" for error reporting.
find-sh-decrement {} +
##### If that completes successfully...
&&
##### Pass through again and remove the ".decremented" prefix.
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented' -exec sh -c 'for f; do mv -i "$f" "${f%.decremented}"; done' find-sh-remove-prefix {} +
Test results:
$ ls
DBGC180_805754 DBGC180_805755 DBGC180_805756
$ cat DBGC180_805754
This file started as DBGC180_805754
$ cat DBGC180_805755
This file started as DBGC180_805755
$ cat DBGC180_805756
This file started as DBGC180_805756
$ find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]' -exec sh -c 'for f; do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented"; done' find-sh-decrement {} + && find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented' -exec sh -c 'for f; do mv -i "$f" "${f%.decremented}"; done' find-sh-remove-prefix {} +
$ ls
DBGC180_805753 DBGC180_805754 DBGC180_805755
$ cat DBGC180_805753
This file started as DBGC180_805754
$ cat DBGC180_805754
This file started as DBGC180_805755
$ cat DBGC180_805755
This file started as DBGC180_805756
$
For extra safety, run the first find
command and inspect the results for yourself before you run the second command to remove the .decremented
suffix.
Run this:
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]'
-exec sh -c 'for f;
do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented";
done' find-sh-decrement {} +
Then inspect results, and then run this:
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented'
-exec sh -c 'for f;
do mv -i "$f" "${f%.decremented}";
done' find-sh-remove-prefix {} +
Why the downvote? This does exactly what was requested, and is quite clean in my opinion.
– Wildcard
Oct 3 '16 at 14:34
add a comment |
Wow, this was trickier than I expected.
As Gilles pointed out, considering the number of files to be handled, you should rename them in a way that won't give you problems if the command is interrupted. The command below does that.
I wrote this command to be fairly robust against failures. Note that we explicitly exclude files where the number has a leading 0; if you have files like that, post a comment and I'll include a command to deal with them.
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]' -exec sh -c 'for f; do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented"; done' find-sh-decrement {} + && find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented' -exec sh -c 'for f; do mv -i "$f" "${f%.decremented}"; done' find-sh-remove-prefix {} +
With line wrappings (can still be copied and pasted):
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]'
-exec sh -c 'for f;
do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented";
done' find-sh-decrement {} + &&
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented'
-exec sh -c 'for f;
do mv -i "$f" "${f%.decremented}";
done' find-sh-remove-prefix {} +
Explanation of the parts (this could use some formatting cleanup):
##### Recursively find regular files in the current directory...
find . -type f
##### whose name matches this exact pattern...
-name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]'
##### and run the following shell script...
-exec sh -c
##### (shell script: ) for every file given as an argument...
'for f;
##### rename the file, prompting for confirmation for any overwrites...
do mv -i
##### from the original file name...
"$f"
##### to the file name decremented by 1, with '.decremented' afterward...
"${f%_*}_$((${f##*_}-1)).decremented";
##### (End of shell script)
done'
##### on as many found files as possible at once,
##### using the name "find-sh-decrement" for error reporting.
find-sh-decrement {} +
##### If that completes successfully...
&&
##### Pass through again and remove the ".decremented" prefix.
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented' -exec sh -c 'for f; do mv -i "$f" "${f%.decremented}"; done' find-sh-remove-prefix {} +
Test results:
$ ls
DBGC180_805754 DBGC180_805755 DBGC180_805756
$ cat DBGC180_805754
This file started as DBGC180_805754
$ cat DBGC180_805755
This file started as DBGC180_805755
$ cat DBGC180_805756
This file started as DBGC180_805756
$ find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]' -exec sh -c 'for f; do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented"; done' find-sh-decrement {} + && find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented' -exec sh -c 'for f; do mv -i "$f" "${f%.decremented}"; done' find-sh-remove-prefix {} +
$ ls
DBGC180_805753 DBGC180_805754 DBGC180_805755
$ cat DBGC180_805753
This file started as DBGC180_805754
$ cat DBGC180_805754
This file started as DBGC180_805755
$ cat DBGC180_805755
This file started as DBGC180_805756
$
For extra safety, run the first find
command and inspect the results for yourself before you run the second command to remove the .decremented
suffix.
Run this:
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]'
-exec sh -c 'for f;
do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented";
done' find-sh-decrement {} +
Then inspect results, and then run this:
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented'
-exec sh -c 'for f;
do mv -i "$f" "${f%.decremented}";
done' find-sh-remove-prefix {} +
Why the downvote? This does exactly what was requested, and is quite clean in my opinion.
– Wildcard
Oct 3 '16 at 14:34
add a comment |
Wow, this was trickier than I expected.
As Gilles pointed out, considering the number of files to be handled, you should rename them in a way that won't give you problems if the command is interrupted. The command below does that.
I wrote this command to be fairly robust against failures. Note that we explicitly exclude files where the number has a leading 0; if you have files like that, post a comment and I'll include a command to deal with them.
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]' -exec sh -c 'for f; do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented"; done' find-sh-decrement {} + && find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented' -exec sh -c 'for f; do mv -i "$f" "${f%.decremented}"; done' find-sh-remove-prefix {} +
With line wrappings (can still be copied and pasted):
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]'
-exec sh -c 'for f;
do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented";
done' find-sh-decrement {} + &&
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented'
-exec sh -c 'for f;
do mv -i "$f" "${f%.decremented}";
done' find-sh-remove-prefix {} +
Explanation of the parts (this could use some formatting cleanup):
##### Recursively find regular files in the current directory...
find . -type f
##### whose name matches this exact pattern...
-name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]'
##### and run the following shell script...
-exec sh -c
##### (shell script: ) for every file given as an argument...
'for f;
##### rename the file, prompting for confirmation for any overwrites...
do mv -i
##### from the original file name...
"$f"
##### to the file name decremented by 1, with '.decremented' afterward...
"${f%_*}_$((${f##*_}-1)).decremented";
##### (End of shell script)
done'
##### on as many found files as possible at once,
##### using the name "find-sh-decrement" for error reporting.
find-sh-decrement {} +
##### If that completes successfully...
&&
##### Pass through again and remove the ".decremented" prefix.
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented' -exec sh -c 'for f; do mv -i "$f" "${f%.decremented}"; done' find-sh-remove-prefix {} +
Test results:
$ ls
DBGC180_805754 DBGC180_805755 DBGC180_805756
$ cat DBGC180_805754
This file started as DBGC180_805754
$ cat DBGC180_805755
This file started as DBGC180_805755
$ cat DBGC180_805756
This file started as DBGC180_805756
$ find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]' -exec sh -c 'for f; do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented"; done' find-sh-decrement {} + && find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented' -exec sh -c 'for f; do mv -i "$f" "${f%.decremented}"; done' find-sh-remove-prefix {} +
$ ls
DBGC180_805753 DBGC180_805754 DBGC180_805755
$ cat DBGC180_805753
This file started as DBGC180_805754
$ cat DBGC180_805754
This file started as DBGC180_805755
$ cat DBGC180_805755
This file started as DBGC180_805756
$
For extra safety, run the first find
command and inspect the results for yourself before you run the second command to remove the .decremented
suffix.
Run this:
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]'
-exec sh -c 'for f;
do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented";
done' find-sh-decrement {} +
Then inspect results, and then run this:
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented'
-exec sh -c 'for f;
do mv -i "$f" "${f%.decremented}";
done' find-sh-remove-prefix {} +
Wow, this was trickier than I expected.
As Gilles pointed out, considering the number of files to be handled, you should rename them in a way that won't give you problems if the command is interrupted. The command below does that.
I wrote this command to be fairly robust against failures. Note that we explicitly exclude files where the number has a leading 0; if you have files like that, post a comment and I'll include a command to deal with them.
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]' -exec sh -c 'for f; do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented"; done' find-sh-decrement {} + && find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented' -exec sh -c 'for f; do mv -i "$f" "${f%.decremented}"; done' find-sh-remove-prefix {} +
With line wrappings (can still be copied and pasted):
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]'
-exec sh -c 'for f;
do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented";
done' find-sh-decrement {} + &&
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented'
-exec sh -c 'for f;
do mv -i "$f" "${f%.decremented}";
done' find-sh-remove-prefix {} +
Explanation of the parts (this could use some formatting cleanup):
##### Recursively find regular files in the current directory...
find . -type f
##### whose name matches this exact pattern...
-name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]'
##### and run the following shell script...
-exec sh -c
##### (shell script: ) for every file given as an argument...
'for f;
##### rename the file, prompting for confirmation for any overwrites...
do mv -i
##### from the original file name...
"$f"
##### to the file name decremented by 1, with '.decremented' afterward...
"${f%_*}_$((${f##*_}-1)).decremented";
##### (End of shell script)
done'
##### on as many found files as possible at once,
##### using the name "find-sh-decrement" for error reporting.
find-sh-decrement {} +
##### If that completes successfully...
&&
##### Pass through again and remove the ".decremented" prefix.
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented' -exec sh -c 'for f; do mv -i "$f" "${f%.decremented}"; done' find-sh-remove-prefix {} +
Test results:
$ ls
DBGC180_805754 DBGC180_805755 DBGC180_805756
$ cat DBGC180_805754
This file started as DBGC180_805754
$ cat DBGC180_805755
This file started as DBGC180_805755
$ cat DBGC180_805756
This file started as DBGC180_805756
$ find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]' -exec sh -c 'for f; do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented"; done' find-sh-decrement {} + && find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented' -exec sh -c 'for f; do mv -i "$f" "${f%.decremented}"; done' find-sh-remove-prefix {} +
$ ls
DBGC180_805753 DBGC180_805754 DBGC180_805755
$ cat DBGC180_805753
This file started as DBGC180_805754
$ cat DBGC180_805754
This file started as DBGC180_805755
$ cat DBGC180_805755
This file started as DBGC180_805756
$
For extra safety, run the first find
command and inspect the results for yourself before you run the second command to remove the .decremented
suffix.
Run this:
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9]'
-exec sh -c 'for f;
do mv -i "$f" "${f%_*}_$((${f##*_}-1)).decremented";
done' find-sh-decrement {} +
Then inspect results, and then run this:
find . -type f -name 'DBGC180_[1-9][0-9][0-9][0-9][0-9][0-9].decremented'
-exec sh -c 'for f;
do mv -i "$f" "${f%.decremented}";
done' find-sh-remove-prefix {} +
edited Apr 13 '17 at 12:36
Community♦
1
1
answered Sep 29 '16 at 6:56
WildcardWildcard
22.9k1065169
22.9k1065169
Why the downvote? This does exactly what was requested, and is quite clean in my opinion.
– Wildcard
Oct 3 '16 at 14:34
add a comment |
Why the downvote? This does exactly what was requested, and is quite clean in my opinion.
– Wildcard
Oct 3 '16 at 14:34
Why the downvote? This does exactly what was requested, and is quite clean in my opinion.
– Wildcard
Oct 3 '16 at 14:34
Why the downvote? This does exactly what was requested, and is quite clean in my opinion.
– Wildcard
Oct 3 '16 at 14:34
add a comment |
Use awk
to create a fully expanded rename script:
find . -name "DBGC180_*" |sort |awk -F "_" '{print "mv -i "$0" "$1"_"$2-1}' >/tmp/rename.sh
You can review the script before executing. This is the unique feature of this solution. Then execute it:
sh -e -x /tmp/rename.sh
Notes
- you may improve the find pattern, the question is not 100% clear about what files has to be renamed.
sort
is important to not overwrite existing files
mv
option-i
makes it extra-safe to never overwrite files
sh
option-e
is to abort the script in case of error
sh
option-x
prints a trace to see what was done so far in case the script is interrupted (to make recovery possible). You could also usemv -v
instead if supported.
Down voters! Please comment whats wrong here.
– rudimeier
Sep 29 '16 at 11:12
Your added explanations are good, and the script may work fine for the exact use case of the Original Poster. However, it is definitely not robust. (My own definition of robust: Does not produce unexpected output in the face of unexpected input.) There are a great many caveats if the script would be modified and used more generally, and you don't note these: (1) It won't handle whitespace correctly, or even underscores, if they appear within directory names (i.e. not truly recursive); (cont'd)
– Wildcard
Sep 29 '16 at 19:51
(cont'd) (2) It won't handle file extensions (see what happens if you give it the fileDBGC180_5555.txt
, for instance); (3) If the script is interrupted partway through there is no way to tell which files have been renamed and which haven't been.
– Wildcard
Sep 29 '16 at 19:51
add a comment |
Use awk
to create a fully expanded rename script:
find . -name "DBGC180_*" |sort |awk -F "_" '{print "mv -i "$0" "$1"_"$2-1}' >/tmp/rename.sh
You can review the script before executing. This is the unique feature of this solution. Then execute it:
sh -e -x /tmp/rename.sh
Notes
- you may improve the find pattern, the question is not 100% clear about what files has to be renamed.
sort
is important to not overwrite existing files
mv
option-i
makes it extra-safe to never overwrite files
sh
option-e
is to abort the script in case of error
sh
option-x
prints a trace to see what was done so far in case the script is interrupted (to make recovery possible). You could also usemv -v
instead if supported.
Down voters! Please comment whats wrong here.
– rudimeier
Sep 29 '16 at 11:12
Your added explanations are good, and the script may work fine for the exact use case of the Original Poster. However, it is definitely not robust. (My own definition of robust: Does not produce unexpected output in the face of unexpected input.) There are a great many caveats if the script would be modified and used more generally, and you don't note these: (1) It won't handle whitespace correctly, or even underscores, if they appear within directory names (i.e. not truly recursive); (cont'd)
– Wildcard
Sep 29 '16 at 19:51
(cont'd) (2) It won't handle file extensions (see what happens if you give it the fileDBGC180_5555.txt
, for instance); (3) If the script is interrupted partway through there is no way to tell which files have been renamed and which haven't been.
– Wildcard
Sep 29 '16 at 19:51
add a comment |
Use awk
to create a fully expanded rename script:
find . -name "DBGC180_*" |sort |awk -F "_" '{print "mv -i "$0" "$1"_"$2-1}' >/tmp/rename.sh
You can review the script before executing. This is the unique feature of this solution. Then execute it:
sh -e -x /tmp/rename.sh
Notes
- you may improve the find pattern, the question is not 100% clear about what files has to be renamed.
sort
is important to not overwrite existing files
mv
option-i
makes it extra-safe to never overwrite files
sh
option-e
is to abort the script in case of error
sh
option-x
prints a trace to see what was done so far in case the script is interrupted (to make recovery possible). You could also usemv -v
instead if supported.
Use awk
to create a fully expanded rename script:
find . -name "DBGC180_*" |sort |awk -F "_" '{print "mv -i "$0" "$1"_"$2-1}' >/tmp/rename.sh
You can review the script before executing. This is the unique feature of this solution. Then execute it:
sh -e -x /tmp/rename.sh
Notes
- you may improve the find pattern, the question is not 100% clear about what files has to be renamed.
sort
is important to not overwrite existing files
mv
option-i
makes it extra-safe to never overwrite files
sh
option-e
is to abort the script in case of error
sh
option-x
prints a trace to see what was done so far in case the script is interrupted (to make recovery possible). You could also usemv -v
instead if supported.
edited Sep 29 '16 at 11:11
answered Sep 27 '16 at 19:53
rudimeierrudimeier
5,5371832
5,5371832
Down voters! Please comment whats wrong here.
– rudimeier
Sep 29 '16 at 11:12
Your added explanations are good, and the script may work fine for the exact use case of the Original Poster. However, it is definitely not robust. (My own definition of robust: Does not produce unexpected output in the face of unexpected input.) There are a great many caveats if the script would be modified and used more generally, and you don't note these: (1) It won't handle whitespace correctly, or even underscores, if they appear within directory names (i.e. not truly recursive); (cont'd)
– Wildcard
Sep 29 '16 at 19:51
(cont'd) (2) It won't handle file extensions (see what happens if you give it the fileDBGC180_5555.txt
, for instance); (3) If the script is interrupted partway through there is no way to tell which files have been renamed and which haven't been.
– Wildcard
Sep 29 '16 at 19:51
add a comment |
Down voters! Please comment whats wrong here.
– rudimeier
Sep 29 '16 at 11:12
Your added explanations are good, and the script may work fine for the exact use case of the Original Poster. However, it is definitely not robust. (My own definition of robust: Does not produce unexpected output in the face of unexpected input.) There are a great many caveats if the script would be modified and used more generally, and you don't note these: (1) It won't handle whitespace correctly, or even underscores, if they appear within directory names (i.e. not truly recursive); (cont'd)
– Wildcard
Sep 29 '16 at 19:51
(cont'd) (2) It won't handle file extensions (see what happens if you give it the fileDBGC180_5555.txt
, for instance); (3) If the script is interrupted partway through there is no way to tell which files have been renamed and which haven't been.
– Wildcard
Sep 29 '16 at 19:51
Down voters! Please comment whats wrong here.
– rudimeier
Sep 29 '16 at 11:12
Down voters! Please comment whats wrong here.
– rudimeier
Sep 29 '16 at 11:12
Your added explanations are good, and the script may work fine for the exact use case of the Original Poster. However, it is definitely not robust. (My own definition of robust: Does not produce unexpected output in the face of unexpected input.) There are a great many caveats if the script would be modified and used more generally, and you don't note these: (1) It won't handle whitespace correctly, or even underscores, if they appear within directory names (i.e. not truly recursive); (cont'd)
– Wildcard
Sep 29 '16 at 19:51
Your added explanations are good, and the script may work fine for the exact use case of the Original Poster. However, it is definitely not robust. (My own definition of robust: Does not produce unexpected output in the face of unexpected input.) There are a great many caveats if the script would be modified and used more generally, and you don't note these: (1) It won't handle whitespace correctly, or even underscores, if they appear within directory names (i.e. not truly recursive); (cont'd)
– Wildcard
Sep 29 '16 at 19:51
(cont'd) (2) It won't handle file extensions (see what happens if you give it the file
DBGC180_5555.txt
, for instance); (3) If the script is interrupted partway through there is no way to tell which files have been renamed and which haven't been.– Wildcard
Sep 29 '16 at 19:51
(cont'd) (2) It won't handle file extensions (see what happens if you give it the file
DBGC180_5555.txt
, for instance); (3) If the script is interrupted partway through there is no way to tell which files have been renamed and which haven't been.– Wildcard
Sep 29 '16 at 19:51
add a comment |
Thanks for contributing an answer to Unix & Linux Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f312748%2frename-multiple-files-to-decrement-number-in-file-name%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
If you were on Mac OS X this would be a perfect use case for Name Mangler.
– Wildcard
Sep 29 '16 at 6:26
1
It's not 100% clear how the input files look like. Do all files have the same prefix DBGC180? Is 805753 the smallest number? Are there numbers with more or less than 6 digits? Are there numbers which shall not be renamed, e.g. <805753?
– rudimeier
Sep 29 '16 at 10:16