I have recently managed to convince my mother to let me switch her PC to Ubuntu, and to make her transition easier I want to automate as many tasks as possible for her. I managed to do quite a bit, however there is a script I'd like to leave her with, but, unfortunately I have no knowledge of scripting.

The purpose would be to rename all text files in a folder (mainly Desktop) named e.g. "note*" (w/out extension) as "note.txt" (for interoperability's sake and easy upload to google docs) and move them in a specially designated folder. The commands I'd need would be:

- find files in current folder named note* (and not ending in .txt) and rename them as note*.txt
- move files named note*.txt to /home/username/notes

Unfortunately I don't know how to put it in script form so I'm asking for help.

5 Answers
5

Open up a terminal, and open up a text editor using this command (gedit, or your favourite!)

gedit ~/.gnome2/nautilus-scripts/Notes

This will open up a file in the Nautilus (file browser) Scripts folder for some magic that you will see soon :D
Now copy the following simplified code into gedit and save. (You can use Marcelo Morales if you want :P)

Now, to see the magic of Nautilus Scripts.
Right click in a folder with a "notes" file or two within, go to Scripts and then click "Notes" and you'll magically see all of your "notes" files turn to "notes*.txt"

No worries, completely looked over the white spaces by accident :S Thanks for the good read, really did notice my bad habits haha Added in changes to my answer to compensate; although, for some reason if the file is called just "notes", it won't change it. I have a feeling that it might be something to do with the wildcards, wanna shed some light on this geirha? :P
–
Alex StevensApr 4 '11 at 14:07

If you run the script in your home directory and the destination directory is ~/notes then it will obviously fail on notes as moving a directory inside itself is not possible. You can use [[ $noteFile -ef $movePath ]] to test if two files are the same (see help test). A few more comments: 1) *"notes"*[^.txt] does not match what you think it matches. 2) In bash4, you can lowercase with parameter expansions, "${noteFile,,}". mywiki.wooledge.org/BashSheet#Parameter_Operations
–
geirhaApr 4 '11 at 21:52

Man, you are a lifesaver. Also, that wiki is BASH gold :P Updated the code, didn't try too many crazy things. Threw in a directory check so that we don't get silly errors.
–
Alex StevensApr 5 '11 at 0:05

Problems! The script is not behaving as expected... When I run the script, it recursively pulls in everything in my home directory with the text "home" in it, and doesn't end in ".txt"
–
Peter.OApr 2 '11 at 15:28

@geirha... Your general idea is on track (I like the globbing), but it has some problems... 1) it doesn't handle filenames with embedded spaces... 2) you are moving the files twice!... 3) it tries to move directories and links named "note*"
–
Peter.OApr 2 '11 at 15:17

@fred.bear 1) It handles any filename, why do you think it doesn't? 2) It's not moving files twice... unless the current directory is "$HOME/notes/". 3) It does, yes. If that's wanted or not, the question doesn't say...
–
geirhaApr 2 '11 at 15:58

@geirha: For 1) It failed to process files with embedded spaces: "note 1" "note 2" .... and for 2) the first mv moves the file out of the current dir, and the second mv is still current in the now "empty" original dir... And in either case, mvallows you to rename and move at the same time; why hit the directory routines twice? ... 3) the question does say... (the) purpose would be to rename all text files in...
–
Peter.OApr 2 '11 at 16:32

Here is the error message for (1): mv: cannot move "notes" to a subdirectory of itself, "/home/fred/notes/notes.txt" That particular file is actually named note 1.
–
Peter.OApr 2 '11 at 16:35

2

@fred.bear that error message is harmless, and not about a file named note 1...
–
geirhaApr 2 '11 at 16:56

A couple of comments on this: 1) I don't see the point in setting and unsetting extglob. When the script starts it will be off. And since it won't affect regular globs, there's no point in turning it off at all. 2) For iterating the array I'd just use for file in "${farray[@]}";. Shorter and easier. 3) A thing we both forgot is to set nullglob to account for no files matching the pattern. 4) Lastly, your script doesn't move the files that DOES end with .txt.
–
geirhaApr 2 '11 at 17:04

:) ..I thought you'd find some things. It's good. About unsetting extglob. I'd thought about it, but as bash scrpting is quite new to me (6 months), I just wanted to try some way of doing it. In longer script it may come in handy (some day) so this was a good place to practice:)... Re itterating the array.. Yes, I suppose that would work. I'm still trying to work our when and where bash-words lose their integrity and word-split.. I gusess that it would save a lot of individual array-element accesses... (thanks).. re "nullglob" I didn't forget :), but it I was on overload, so I ignored it.
–
Peter.OApr 2 '11 at 17:44

...continued: Re the .txt extension, he does say "named e.g. "note*" (w/out extension)" ... but now I understand why your updated script actually catered for the extension to be included in the shell filename expansion.... btw.. Your new updated method looks great.. nice and simple and straight forward... and the .txt is easily tweaked either way.... It's very late here ..must go... bye :)
–
Peter.OApr 2 '11 at 17:52

bear Well, it doesn't make sense to disable extglob. nullglob, however, makes more sense to disable as soon as it's not needed anymore. nullglob will have "surprising" effects if you don't have full control of which expansions take place at which point. Note that shopt nullglob will return false if it's unset, and true if it's set. Much better to just test the return value, rather than string-comparison. See mywiki.wooledge.org/Arguments for a thorough explanation of word splitting.
–
geirhaApr 2 '11 at 19:03

Would it work with filenames that have white spaces?. At first sight it seems it does not.
–
Marcelo MoralesMar 31 '11 at 22:59

note*[^.txt] will match all files starting with note and not ending with a ., t or x. Also see mywiki.wooledge.org/BashPitfalls.
–
geirhaApr 1 '11 at 22:01

you are correct! bash is kind of irritating. I've been trying other methods, like for my_file in $((ls note*.txt; ls note*) | sort | uniq -u); do mv $my_file /where/ever; done but that doesn't handle spaces correctly. :( There is an IFS variable you can mess with, but that is beyond my bash skills.
–
user1974Apr 2 '11 at 16:41

@user1974 ls outputs a representation of files, not filenames, they just happen to be the same for simple cases (e.g. where there's no odd characters in the filenames). IFS will allow you to handle a few more cases, but it's by no means a solution. ls should really never be used in a script. See fred.bear and mine's answers for a glob that'll do what you want. Also, don't forget quotes.
–
geirhaApr 2 '11 at 19:10

@user1974. Just a bit more about using "quoted filenames".. In both mine and geirha's examples, you will see the filename being used without quotes (but not everywhere). This is because the construct [[ ... ]] does not do any word-splitting, so with or without quotes is okay there .. Note that the older single-bracket version does not "protect" variables in this way, so you do need quotes there when whitespace may be involved... More double-brackets: ((...)) is for integer conditions ((x==1)) and assignment/calculation ((x+=1)); you don't need $ or whitespace with integers.
–
Peter.OApr 3 '11 at 10:31