How to rename/move all files with a certain extension?
Question
I'm learning tcl (expect) and now I came to an interesting issue. I need a command to move/rename a bunch of files with extension .status. I tried these:
spawn /bin/mv *.status some_dir
exec /bin/mv *.status some_dir
Of course, that did not work. I googled a bit and found something about glob, but it doesn't seem to work the way I want it to. If I do:
exec /bin/mv [glob *.status] somedir
mv complains that '1.status 2.status 3.status...etc.' is not a valid file. It as if the whole list of files is concatenated in a single string instead of being treated separately.
Trying to find more information via google lead me to a lot of broken and outdated links, so I'm hoping beside solving this problem, could you point me to some good online resource for tcl/expect basics and common pitfalls.
Update: Only solutions that use standard tcl and standard tools in /bin will be accepted.
Solution
$ ls -1 1.status 2.status rename.tclsh* some_dir/ two words.status $ cat rename.tclsh #!/usr/local/bin/tclsh eval exec /bin/mv [glob *.status] some_dir $ ./rename.tclsh $ ls -1 rename.tclsh* some_dir/ $ ls -1 some_dir/ 1.status 2.status two words.status
OTHER TIPS
Randy's answer is short and correct but uses an exec without need. Joseph's answer is very robust but a bit long.
For a short and idiomatic answer I would use (requires Tcl 8.5):
file rename {*}[glob *.status] some_dir
proc move_to_dir {filenames dirname} {
foreach filename $filenames {
file rename $filename [file join $dirname [file tail $filename]]
}
}
# Example:
move_to_dir [glob -nocomplain *.status] ~/foo/bar/
This solution works with files with names containing spaces, when there is a lot of files etc:
exec find -maxdepth 1 -name *.status -print0 | xargs -0 mv -t some_dir
But it needs find and xargs which are most often in /usr/bin, not /bin.
As a safety feature when using complex 'find' commands and potentially deleting data I stick an 'echo' in front of the command and capture it to a file.
I can then check the commands listed in the file before using 'source' to run it.
It's also a way of handling those occasional edge case files manually.