views:

89

answers:

2

I am trying to use the output from 'mdfind' to create a bunch of symlinks. Output of 'mdfind' is like this:

/pathtofile1/
/pathtofile2/
/pathtofile3/

So, I used 'sed' to add 'ln -s ' to the start of each line, and awk {print $0 "/directory where I want this/"};

after my single-line script successfully outputs this:

ln -s "/pathtofile1/" "/directory where I want this"
ln -s "/pathtofile2/" "/directory where I want this"
ln -s "/pathtofile3/" "/directory where I want this"

Problem is, when I run this, I get this error: "/directory where I want this: File does not exist"

The weird thing is that when I run these lines individually, they links are created as expected, but running the entire command returns the error above.

Any ideas?

I don't think that this is the ideal way to do what I'm trying to do, so let me know if you have any better solutions.


Edited with more information.

#! /bin/bash
itemList=`mdfind -s "$1"| awk '{ print "ln -s \""$0"\" \"/Users/username/Local/Recent\""}'`
echo "$itemList"
`$itemList`

$1 is a test *.savedSearch that returns a list of files.

My result (from the echo) is:

ln -s "/Users/username/Dropbox/Document.pdf" "/Users/username/Local/Recent"
ln -s "/Users/username/Dropbox/Document2.pdf" "/Users/username/Local/Recent"

and the error that I get is:

ln: "/Users/username/Local/Recent": No such file or directory

But, if I run a copy-pasted of each line individually, the links are created as expected.

A: 

It would be much easier to determine what the problem was if you used some actual, or at least plausible, paths as examples, but ln isn't going to create these directories for you if that's what you want.

Azeem.Butt
I'm not hoping to create directories - in fact the directory exists because, as I said above, that the lines individually run just fine. For instance if I add | head -1, the command will run.
Andrew J. Freyer
So post your actual source and an actual example of some actual input
Azeem.Butt
Why don't you loop over your results individually instead of packing them all into one big string?
Azeem.Butt
I've been goofing with that possibility, having issues calling it line by line. Any idea why this doesn't work? Is this an uncommon strategy?
Andrew J. Freyer
I'd say throwing backticks around a multi-line string and expecting it to do anything useful is pretty uncommon, but someone else may have a different opinion.
Azeem.Butt
I've been successful using this in the past, specifically with killing an entire list of duplicate processes. "kill 123kill 456kill 234"Kills all processes... maybe that's a special case.
Andrew J. Freyer
using 'eval' works just fine.
Andrew J. Freyer
+1  A: 

One way to keep it simple:

mdfind -0 "query" | ( cd "/Users/username/Local/Recent" ; xargs -0 -I path ln -s path . )

This is of course doesn't handle duplicate file names, etc.

EDIT:

The reasons your solution is failing is that, first, the contents of $itemList is being executed as one long command (i.e. the line feeds output by awk are ignored), and then, second, the command substitution occurs before quote removal. What is actually processed is roughly equivalent to:

ln '-s' '"/pathtofile1/"' '"/to"' 'ln' '-s' '"/pathtofile2/"' '"/to"' 'ln' '-s' '"/pathtofile3/"' '"/to"'

/bin/ln recognizes this as the:

ln [-Ffhinsv] source_file ... target_dir

form of the command and checks to see that the final parameter is an existing directory. That test fails because the directory name includes the surrounding quote marks. Note carefully the error message you report and compare:

$ ln a b c "/Users/username/Local/Recent"
ln: /Users/username/Local/Recent: No such file or directory
$ ln a b c '"/Users/username/Local/Recent"'
ln: "/Users/username/Local/Recent": No such file or directory

So the morals of the story are, when you are dealing with file names in a shell, the safest solution is to avoid shell processing of the file names so you don't have to deal with quoting and other side effects (which is a big advantage of an xargs solution) and keep it simple: avoid constructing complex multi-line shell commands. It's too easy to get unexpected results.

Ned Deily