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

willcapellaro

macrumors 6502
Original poster
Oct 20, 2011
347
7
I made myself a nice Automator, "Copy File Path as Text" that I use in a right-click regularly. However, it's still not as useful as windows letting you see the full file path and having that be a clickable link, which I want to be able to send out to my team.

I am looking to for a generally tidy way to do some text/string substitution of file paths. Automator does not seem to allow this (I was aiming to build that in to the action)

I need the Mac-formatted path:
/Volumes/SFTP/bobfolder/incoming/ID/ClientKickstarter-Video/kiskstartervideo_01_27_2014.mp4
To to be converted to a Windows-formatted path:
\\ftp\SFTP\bobfolder\incoming\ID\ClientKickstarter-Video\kiskstartervideo_01_27_2014.mp4

So I need to do some \ / and other subs. Seems easy, I just need a tool to do it. Sucks that automator can't.

As long as I'm sending out correct paths, and don't have to manually edit, I will be happy downloading an app or building something. What's my best way to get this to work?
 
Please list the exact Automator actions in your workflow. Be specific. The list should be detailed enough that someone else can exactly replicate your current workflow.

Since you mentioned right-click, I assume the workflow is a Service. Correct? So also describe exactly what selected types your Service receives as input, in what form.

A shell script can do the replacements on the path, but without seeing the rest of the steps (actions), it's difficult to tell you where the action with the shell script would go.
 
Please list the exact Automator actions in your workflow. Be specific. The list should be detailed enough that someone else can exactly replicate your current workflow.

Since you mentioned right-click, I assume the workflow is a Service. Correct? So also describe exactly what selected types your Service receives as input, in what form.

A shell script can do the replacements on the path, but without seeing the rest of the steps (actions), it's difficult to tell you where the action with the shell script would go.

Thanks for responding. After searching, I was gathering that it would not be possible through an Automator workflow (service). But maybe I was wrong, I haven't used Shell scripts before though.

To answer your question, yes, it's a Service. Really simple:

Service receives select [files or folder] in [Finder.app]
Copy to Clipboard

I added a screenshot.
 

Attachments

  • Copy Path as Text.png
    Copy Path as Text.png
    142.2 KB · Views: 172
Try this and post how it works (or not).

1. Add a "Run Shell Script" action immediately before your "Copy to Clipboard" action.

2. Copy and paste this exact line into the "Run Shell Script" action, completely replacing the default command "cat":
Code:
awk '{ sub("Volumes", "/ftp"); print $0 }' | tr '/' '\'

3. Save the Service.

4. Test it in Finder.

5. Paste the clipboard into TextEdit and observe that /'s have been converted to \'s.

The result in step 5 should be what you asked for. If you don't get the expected results in step 5, then screenshot your Automator workflow and post it. Also post what input file you tested it on, and what the clipboard actually was.

This shell script is limited. It requires "Volumes" to be at the start of the pathname, which it replaces with "/ftp", then converts every '/' to a '\'. If there is no "Volumes", then no replacement occurs, only the slash-to-backslash conversion.
 
Your solution.

That worked perfectly. I can post results but it's taking extra time because I have to redact project names/etc... screenshots would be even more work. But I'm happy to share if this is useful for posterity.

To teach me (others who may read this) to fish: Please tell me what language I'm using in the shell script, what sort of operators I'm looking for if I want to learn that language.

Meanwhile, my next step is to make this more robust, and be able to do this action from the ftp volume and a project server, and add more as needed.

So I got the new one, the project server, to work, using your script as a model. But I can't get it to work together with the ftp script you gave me. Tried a few ways that will probably just irritate you (same script, different scripts)

Sometimes the second script will get ignored. Often there will be no clipboard output.

Here are the two scripts that I'd like to work together:

awk '{ sub("Volumes/SFTP", "/ftp/SFTP"); print $0 }' | tr '/' '\'
awk '{ sub("/Volumes/projects", "M:"); print $0 }' | tr '/' '\'

The way around is to create two services, and that's what I'll do if I have to.

Thank you kindly for your awesomeness.
 
Meanwhile, my next step is to make this more robust, and be able to do this action from the ftp volume and a project server, and add more as needed.

So I got the new one, the project server, to work, using your script as a model. But I can't get it to work together with the ftp script you gave me. Tried a few ways that will probably just irritate you (same script, different scripts)

Sometimes the second script will get ignored. Often there will be no clipboard output.

Here are the two scripts that I'd like to work together:

awk '{ sub("Volumes/SFTP", "/ftp/SFTP"); print $0 }' | tr '/' '\'
awk '{ sub("/Volumes/projects", "M:"); print $0 }' | tr '/' '\'

The way around is to create two services, and that's what I'll do if I have to.

Thank you kindly for your awesomeness.
Rather than you guessing what the scripts should be, it's better if you tell me what the inputs and outputs are. You had a nice clear and concise description of the inputs and outputs in your first post. Please do something like that again.

I don't entirely understand your intent for the "two scripts you'd like to work together", because I don't know what the results should be. I can guess, but then we're going around in circles, where I'm guessing what your guess at a shell script should do, but because you don't know shell scripting, I have to guess what you might have meant in your guess, and then guess what the actual inputs will be, so I can then guess what outputs you want.

My guess is that there are two separate initial patterns you want to match and replace, but that turns out to be much easier to do with a very different script. But that's just my guess.

Overall, there's way too much guessing, and not enough specification of expected inputs and outputs. If you need something flexible and extensible, please state that. I can probably make something work, and if I can't I'll tell you. But I need to know the scope along with the specifics of inputs and outputs.


The shell script contains two commands, awk and tr. The output of awk is fed to the input to tr. This arrangement is called a "pipeline" in bash, which is the overarching command-line language that interprets commands.

Both awk and tr have man pages, which are summaries or descriptions of how the commands work, and are written for those with experience in Unix commands. Here's the online links, but don't expect to understand them just by reading the man pages:
https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/awk.1.html
https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/tr.1.html

Awk is a "little language" designed specifically for working on text, and more specifically on lines of text. The small program I gave it tells it to replace the first appearance of the substring "Volumes" with "/ftp", and then print the result.

Tr is a character conversion tool. The parameters I gave it tell it to translate each '/' to a '\'.

When the two commands are arranged in a pipeline (this part is provided by bash), the output of awk is fed to the input of tr, and both actions end up being performed in sequence. The output from tr is text, and that's then fed to the next Automator action.


Bash has a man page, too, but it's pretty much impossible to learn bash scripting from if you have no experience. It's intended for someone already familiar with what a shell does, and a lot of other things. Your best bet there is a book like this:
http://shop.oreilly.com/product/9780596009656.do
 
Rather than you guessing what the scripts should be, it's better if you tell me what the inputs and outputs are. You had a nice clear and concise description of the inputs and outputs in your first post. Please do something like that again.

I don't entirely understand your intent for the "two scripts you'd like to work together", because I don't know what the results should be. I can guess, but then we're going around in circles, where I'm guessing what your guess at a shell script should do, but because you don't know shell scripting, I have to guess what you might have meant in your guess, and then guess what the actual inputs will be, so I can then guess what outputs you want.

My guess is that there are two separate initial patterns you want to match and replace, but that turns out to be much easier to do with a very different script. But that's just my guess.

Overall, there's way too much guessing, and not enough specification of expected inputs and outputs. If you need something flexible and extensible, please state that. I can probably make something work, and if I can't I'll tell you. But I need to know the scope along with the specifics of inputs and outputs.


The shell script contains two commands, awk and tr. The output of awk is fed to the input to tr. This arrangement is called a "pipeline" in bash, which is the overarching command-line language that interprets commands.

Both awk and tr have man pages, which are summaries or descriptions of how the commands work, and are written for those with experience in Unix commands. Here's the online links, but don't expect to understand them just by reading the man pages:
https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/awk.1.html
https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/tr.1.html

Awk is a "little language" designed specifically for working on text, and more specifically on lines of text. The small program I gave it tells it to replace the first appearance of the substring "Volumes" with "/ftp", and then print the result.

Tr is a character conversion tool. The parameters I gave it tell it to translate each '/' to a '\'.

When the two commands are arranged in a pipeline (this part is provided by bash), the output of awk is fed to the input of tr, and both actions end up being performed in sequence. The output from tr is text, and that's then fed to the next Automator action.


Bash has a man page, too, but it's pretty much impossible to learn bash scripting from if you have no experience. It's intended for someone already familiar with what a shell does, and a lot of other things. Your best bet there is a book like this:
http://shop.oreilly.com/product/9780596009656.do

I used the previous script you gave me
awk '{ sub("Volumes/SFTP", "/ftp/SFTP"); print $0 }' | tr '/' '\'

I changes what is in the sets of double quotes to make another script
awk '{ sub("/Volumes/projects", "M:"); print $0 }' | tr '/' '\'

They each work, but only independently. In my new screenshot, I show them both enabled, but they only work if one is disabled.

The first one you know, that dealt with an ftp server. Note: I added a little additional text to the input and output strings, so it would be able to differentiate between Volumes/SFTP and /Volumes/projects. The second needs to do a similar conversion, to a project server.

So I'm looking to convert this type of server location (with all script disabled):
/Volumes/projects/z_General
to this Windows Formatted one:
M:\z_General

I cobbled together a new script from the one you gave me. And I'm aiming to make the script(s) smart enough to be able to determine which volume it's coming from.

Otherwise it is easy for me at this point to save the existing service as "Save Path as Text (FTP)" and the new one as "Save Path as Text (Projects)"

I need to re-read your recent post and check the links, but I wanted to give you the clarification you asked for. This is no big rush and at this point I'm idly curious. I am sure you have other projects to tend to as well.

Thanks again.
 

Attachments

  • Screen Shot 2014-01-27 at 8.13.35 PM.png
    Screen Shot 2014-01-27 at 8.13.35 PM.png
    64.6 KB · Views: 108
Last edited:

I just re-read your post. Good stuff. If it's another level of magnitude of complexity to make the script work two ways, I'm fine without it. Brain might explode. Two Dropdowns services will work just fine.

You gave me some great links and I will check them out.
 
Your clarification of the inputs and outputs is enough for me to go on. And since you're not in a hurry, I'll probably get back to this tomorrow (Tue).

I recommend not spending too much time with this. You're not going to get it to work the way you're going at it. It'll make sense after I post an update, and I'll explain it then.

Unless someone else takes a shot at it.
 
Try this :

Code:
awk '{ if (/^\/Volumes\/SFTP/) { sub("Volumes/SFTP", "/ftp/SFTP"); print $0 } else if (/^\/Volumes\/projects/) { sub("/Volumes/projects", "M:"); print $0 } }' | tr '/' '\'
 

Attachments

  • Picture 1.png
    Picture 1.png
    197.9 KB · Views: 110
  • Picture 2.png
    Picture 2.png
    151 KB · Views: 106
Put this as the entire script of a single "Run Shell Script" action:
Code:
awk '{ 
  sub("^/Volumes/SFTP/", "//ftp/SFTP/")
  sub("^/Volumes/projects/", "M:/")
  gsub("/", "\\")
  print $0 
}'
Follow it with the "Copy to Clipboard" action.

There only needs to be one "Run Shell Script" action. This single script finds and replaces both of the patterns you asked for. It also does the '/' to '\' conversion, so the 'tr' command is no longer needed.


This script relies on some specialized awk features.

First, if the sub() function, which performs substitutions, doesn't find the requested pattern, then it has no effect. Therefore, overt conditionals (such as kryten2's use of 'if') aren't strictly necessary.

Second, the '^' at the start of the pattern means the rest of the pattern must be at the start of the string in order to match. For example, it will match "/Volumes/SFTP/example", but not "/Users/aname/test/Volumes/SFTP/sample".

So the 1st sub() only matches and replaces within lines that start with the pattern "/Volumes/SFTP/", and the 2nd sub() only matches and replaces within lines that start with its pattern.

The gsub() then replaces every instance of '/' with '\', in any line that has any slashes. As with sub(), it has no effect on lines without its pattern (i.e. lines without slashes).

Finally, the print $0 prints the resulting line, which may have been acted on by 0, 1, or 2 replacement operations.

I tried to make this as simple as possible but still readable, so if you have to change it or extend it in the future it won't take deep knowledge of awk or bash. However, if you run into problems changing it, feel free to ask again.

(I didn't expect to get to this tonight, but I had to order some equipment that I'm now waiting on, so I took advantage of my copious free time.)
 
Put this as the entire script of a single "Run Shell Script" action:
Code:
awk '{ 
  sub("^/Volumes/SFTP/", "//ftp/SFTP/")
  sub("^/Volumes/projects/", "M:/")
  gsub("/", "\\")
  print $0 
}'
Follow it with the "Copy to Clipboard" action.

There only needs to be one "Run Shell Script" action. This single script finds and replaces both of the patterns you asked for. It also does the '/' to '\' conversion, so the 'tr' command is no longer needed.


This script relies on some specialized awk features.

First, if the sub() function, which performs substitutions, doesn't find the requested pattern, then it has no effect. Therefore, overt conditionals (such as kryten2's use of 'if') aren't strictly necessary.

Second, the '^' at the start of the pattern means the rest of the pattern must be at the start of the string in order to match. For example, it will match "/Volumes/SFTP/example", but not "/Users/aname/test/Volumes/SFTP/sample".

So the 1st sub() only matches and replaces within lines that start with the pattern "/Volumes/SFTP/", and the 2nd sub() only matches and replaces within lines that start with its pattern.

The gsub() then replaces every instance of '/' with '\', in any line that has any slashes. As with sub(), it has no effect on lines without its pattern (i.e. lines without slashes).

Finally, the print $0 prints the resulting line, which may have been acted on by 0, 1, or 2 replacement operations.

I tried to make this as simple as possible but still readable, so if you have to change it or extend it in the future it won't take deep knowledge of awk or bash. However, if you run into problems changing it, feel free to ask again.

(I didn't expect to get to this tonight, but I had to order some equipment that I'm now waiting on, so I took advantage of my copious free time.)

That works great. Thank you kindly.

----------

Try this :

Code:
awk '{ if (/^\/Volumes\/SFTP/) { sub("Volumes/SFTP", "/ftp/SFTP"); print $0 } else if (/^\/Volumes\/projects/) { sub("/Volumes/projects", "M:"); print $0 } }' | tr '/' '\'

Thanks for contributing.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.