views:

560

answers:

6

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.

A: 

The mmv command may be what you are looking for. You may need to install it first, though. It's included in the Debian system (www.debian.org), if you can't find it elsewhere.

Lars Wirzenius
Thanks, but I'm trying to find a solution using standard tools. I can't expect my users to install mmv or some other non-standard tool just to get this small script to run.
Milan Babuškov
A: 
$ 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
Randy Proctor
Looks great. Would you mind explaining to a tcl newbie why [list exec /bin/mv] is needed here?
Milan Babuškov
Actually I think that part is redundant. Edited.
Randy Proctor
There's no need to exec an external program to make this work. Tcl has robust file handling commands. Of course, if the exec works and lets you move on to other tasks that's great. For people stumbling on to this question later it's important to point out you can do this in a cross-platform way without resorting to exec.
Bryan Oakley
I don't think what is be invoked is as important as how to invoke it. Replace mv with any arbitrary command and the problem still stands.
Randy Proctor
A: 

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.

Tometzky
+2  A: 
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/
Joseph Bui
A: 

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.

Martin Beckett
+3  A: 

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

Hugge