Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

macstatic

macrumors 68020
Original poster
Oct 21, 2005
2,025
165
Norway
I'm trying to create an Automator application which will "touch" all files (or a folder with files inside) dragged to it. Searching through forums etc. I found the following which I've tested in the OSX terminal and seems to work:

Code:
find . -type f -exec touch {} +

So I've added this to an Automator "Run shell script" action like this:
Code:
for f in "$@"
do
    find . -type f -exec touch {} +
done

When I run it nothing seems to happen (the Automator cogwheel in the Finder menubar spins indefinitely), so I cancel the task. Then after a while lots of files have their modification dates "touched" including ones outside the folder with the files I dragged to it!

Apparently I can't just paste the terminal code into a "Run shell script" action, so what's the correct syntax for doing this, and how do I prevent touch from touching files outside its surrounding folder?
 
Automator's Run Shell Script action uses a default shell, so you need to pay more attention when using paths since your user's setup and environment are not used.

You should probably read up on shell scripting instead of just pasting in stuff found online - your script tried to touch every file in your user directory for each item passed to it, so yes, it would take a while to run. if you are going to use an input argument ("$f" for your example) to determine where to search, you will need to use it with your find command instead of the current directory (note that you won't need to use find at all if an input item is a file).
 
Oops! :oops:
It seems I've updated every single file's modification date, regardless of where they are. Oh well, at least it's not the creation date which has been messed up.

Would I need to use an input argument in order to have files or folders (with files within which should be touched) dragged to the script's dock icon?
 
Yes, you will need to use input arguments if you want to send the desired files and/or folders to your script. Automator sends the output of an action to the following action, so you can use an action such as Ask For Finder Items in a workflow to get input items. If you save as an application, dropped items will be passed to the workflow, so you don't need additional actions to get them.

You will also need to filter for folders, or add a comparison statement in your script so that you can use the appropriate command - for example, the following workflow will ask for items:

1) Ask For Finder Items (set options as desired)
2) Run Shell Script (pass input as arguments):
Code:
for f in "$@"
do
    if [ -d "$f" ]
    then
        find "$f" -type f -exec touch {} +
    else
        touch "$f"
    fi
done
 
I think I understand...
so the additional code in the script is there to only to tell the files (and files from within folders) where to go, while the actual terminal command is the same with the exception of using "$f" instead of "." because that's the only way it knows how to see the file and thereby process it?
Does this also mean that I could use the same script for other similar tasks (a terminal command used to process files) by just exchanging the terminal command part with something else (again, replacing "." with "$f")?

As for the Ask for Finder items action: are you saying I don't need it at all if I'm writing an Automator application (as opposed to an Automator Workflow or Service for instance), or I don't need any other action in addition to Ask for Finder items?
It seems to be pre-definable for specific folders ("Start at:"), so I don't understand how it could be used to drag & drop files or folders onto it.

Finally, the command itself:
Code:
find "$f" -type f -exec touch {} +

I'm worried that it'll touch all the files on my entire drive again.. can you please explain how the above command works? Does is the {} + some sort of wildcard which, if not limited by the filtering done earlier in the script, will affect everything anywhere?
 
In shell scripting, you can use various commands with control statements and variables, like any other programming language. Again, you should probably take a look at some shell scripting books or documentation to understand at least a little bit about what you are doing, since it is fairly easy to make a mess of things (as you have found out). I don't use Bash all that much, but some handy web pages are:
http://mywiki.wooledge.org/BashGuide
http://ss64.com/osx/

You can look at the find man page (or the man page for any command) to find information about what it does and how to use it. For find, you give it the path of a directory to go into, and you can use an expression that is evaluated for each file found in the directory.

The statement for f in "$@" starts a loop, with the variable f being set to an item in the items passed ("$@"). In the case of the exec primary, it runs the named utility, replacing {} with the pathnames. So your statement runs the find command for each directory (represented by the variable $f) in the passed items, then passes the files found to the touch command. In my example, I also do a quick check to see if the item is a file, in which case find doesn't need to be used.

When you create an Automator application, at the top of the document it starts with "Application receives files and folders as input", so dragging files and folders onto the application will pass them on to the actions in your application. If you are just using a workflow, you will need to provide files and folders by some other means, such as the Ask For Finder Items.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.