0

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.

Community
  • 1
  • 1
Andrew J. Freyer
  • 591
  • 2
  • 12
  • 38
  • changed this to just use 'awk' and the error is still happening... – Andrew J. Freyer Dec 18 '09 at 21:56
  • Did any of the solutions help? (It's considered good SO etiquette to either mark one answer as accepted or explain better what you are looking for.) – Ned Deily Dec 20 '09 at 08:44
  • One of your problems is the last line of your script, which contains `$items` in back-quotes. hat flattens the list into a single line, executes it, and captures the standard output (there is none), and then executes that empty string! Suggestion: output a semi-colon in the `awk` after the second quote enclosing the target directory name. This will leave you with valid shell. Then, when it comes to executing the 'script', don't enclose it in backquotes. You might need an `eval`, or you could simply pipe the output of the `awk` script into `sh` (or `bash`), optionally with a `-x` to trace. – Jonathan Leffler Aug 29 '12 at 00:53

2 Answers2

1

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
  • 83,389
  • 16
  • 128
  • 151
0

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
  • 5,855
  • 1
  • 26
  • 22
  • 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 Dec 18 '09 at 22:38
  • So post your actual source and an actual example of some actual input – Azeem.Butt Dec 18 '09 at 22:51
  • Why don't you loop over your results individually instead of packing them all into one big string? – Azeem.Butt Dec 18 '09 at 23:14
  • 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 Dec 18 '09 at 23:22
  • 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 Dec 18 '09 at 23:26
  • I've been successful using this in the past, specifically with killing an entire list of duplicate processes. "kill 123 kill 456 kill 234" Kills all processes... maybe that's a special case. – Andrew J. Freyer Dec 18 '09 at 23:30