With zsh
:
$ autoload zmv
$ n=0; zmv -n '(*.)<->(*.ctl)(#qn)' '$1$[++n]$2'
mv -- SSt12.precip.374.sub.climatology.ctl SSt12.precip.1.sub.climatology.ctl
mv -- SSt12.precip.2874.sub.climatology.ctl SSt12.precip.2.sub.climatology.ctl
mv -- SSt12.precip.3764.sub.climatology.ctl SSt12.precip.3.sub.climatology.ctl
mv -- SSt12.precip.6774.sub.climatology.ctl SSt12.precip.4.sub.climatology.ctl
(do it again without the -n
to actually perform the renaming).
With GNU tools and assuming filenames don't contain newline characters, you could do:
ls -v | awk -F. -vOFS=. -vORS='\0' '/\.ctl$/{print;$3=++n;print}' |
xargs -r0n2 echo mv --
(remove the echo
to actually do the renaming)
One solution is to use the nospace
option for the complete
builtin.
First, you need to know how completion is defined for ls
$ complete -p ls
complete -F _longopt ls
Then you modify it by adding -o nospace
$ complete -o nospace -F _longopt ls
Thus, even if you hit Tab ↹ multiple times, there will be no match and no argument will be added to the command line.
Side effect: you need to manually append a space at the end of the line if you want to add another argument to ls
.
To avoid this side effect you could modify the _longopt
function in a way that prevents it from matching the same argument twice (it might not be straightforward).
How to apply this to other commands and to make it permanent
Appending a trailing space after a match is the default behavior. I don't know if there's a way other than using -o nospace
when specifying completion rules with complete
.
Moreover, keep in mind, that completion rules are specified somewhere, even for builtin commands (on my laptop in this folder: /usr/share/bash-completion
).
If you look at the file /usr/share/bash-completion/bash-completion
you'll find where completions are defined for ls
:
complete -F _longopt a2ps awk base64 bash bc bison cat chroot colordiff cp \
csplit cut date df diff dir du enscript env expand fmt fold gperf \
grep grub head irb ld ldd less ln ls m4 md5sum mkdir mkfifo mknod \
mv netstat nl nm objcopy objdump od paste pr ptx readelf rm rmdir \
sed seq sha{,1,224,256,384,512}sum shar sort split strip sum tac tail tee \
texindex touch tr uname unexpand uniq units vdir wc who
You see that the same rules apply for a whole bunch of different commands (such as cp
,mv
,rm
...), so if you modify this by adding -o nospace
, the changing will affect ls
and all this other commands.
If you're not comfortable with modifying global settings (you'll need root privileges), you can write them to ~/.bash_completion
(create this file, if not present), like this
complete -F _longopt -o nospace a2ps awk base64 bash bc bison cat chroot colordiff cp \
csplit cut date df diff dir du enscript env expand fmt fold gperf \
grep grub head irb ld ldd less ln ls m4 md5sum mkdir mkfifo mknod \
mv netstat nl nm objcopy objdump od paste pr ptx readelf rm rmdir \
sed seq sha{,1,224,256,384,512}sum shar sort split strip sum tac tail tee \
texindex touch tr uname unexpand uniq units vdir wc who
If you wish to modify completions for other commands not listed here, just look up for them in /usr/share/bash-completion/bash-completion
file or /usr/share/bash-completion/completions
folder.
Best Answer
You might do it like:
You would at once assure that multiple instances cannot secure the same name for any given file, and increment your variable.
The
/dev/null
< stderr just drops the shell's complaint about a file existing when it tries to do the output truncate/redirect and finds an existing target. While noclobber is enabled it won't overwrite another file - it will onlyopen()
a new one unless you use>|
. And so you don't need its complaint because the whole point is to increment over existing files until a non-existing name is found.Regarding the performance aspect - it would be better if you didn't start at zero. Or, if you tried to make up the difference. I guess the above might be improved somewhat like:
...but up to 1000 you probably don't have to worry about it terribly. I've got to 65k over random names in a couple seconds.
By the way - you might think you could just:
...but it doesn't work in a
bash
shell.For whatever reason
bash
does the assignment in some other context for redirections - and so the expansions happen in a strange order. So you need a separate simple command to expand the correct$num
value as I get here with&&
. Otherwise, though: