Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I received a great function for highlighting files in Apple's finder using the command-line. It's basically a wrapper for osascript.

I got it from Mac OS X: How to change the color label of files from the Terminal and it looks like this,

# Set Finder label color
label(){
  if [ $# -lt 2 ]; then
    echo "USAGE: label [0-7] file1 [file2] ..."
    echo "Sets the Finder label (color) for files"
    echo "Default colors:"
    echo " 0  No color"
    echo " 1  Orange"
    echo " 2  Red"
    echo " 3  Yellow"
    echo " 4  Blue"
    echo " 5  Purple"
    echo " 6  Green"
    echo " 7  Gray"
  else
    osascript - "$@" << EOF
    on run argv
        set labelIndex to (item 1 of argv as number)
        repeat with i from 2 to (count of argv)
          tell application "Finder"
              set theFile to POSIX file (item i of argv) as alias
              set label index of theFile to labelIndex
          end tell
        end repeat
    end run
EOF
  fi
}

I put it in via vim .bash_profile, ran source .bash_profile and was able to run the function with label 2 /Users/brett/Desktop/test.txt. Perfect.

But what if I'm updating all our old PHP mysql_query( statements to PDO and I want to visually highlight the files I need to edit?

I would normally run,

find /Users/brett/Development/repos/my-repo/ -name "*.php" -print0 | xargs -0 grep -Iil 'mysql_query(' | xargs -I '{}' -n 1 label 2 {}

But it returns,

xargs: label: No such file or directory

I read that I should try running export -f label, but that doesn't seem to help either.

Does anyone know how I can pipe paths/files from grep through xargs to a .bash_profile function?

share|improve this question
3  
Nothing to do with piping nor with .bash_profile. xargs can not execute functions. –  manatwork Aug 1 '13 at 18:22
    
I never knew! Thanks for the info. –  bafromca Aug 5 '13 at 5:35

3 Answers 3

up vote 4 down vote accepted

To call label with xargs you could try something like this:

export -f label
find /Users/brett/Development/repos/my-repo/ -name "*.php" -print0 |
  xargs -0 grep -Iil 'mysql_query(' |
  xargs -I {} -n 1 bash -c 'label 2 {}'

Note how label 2 {} in the latter xargs call has been changed to bash -c 'label 2 {}'. As xargs cannot call the function directly, we export the label function to child bash processes of the parent shell, then fork a child shell and process the function there.

Notes:

  • ~/.bash_profile is typically not sourced by non-login shells, so export -f label is needed to export the label function to the shell invoked by xargs.

  • The -c option tells bash to read commands to be executed from the option argument string.

share|improve this answer

Why don't you just do it the other way around? Find the files in question and process them in a loop instead of using xargs. So many answers in this and other sites recommend xargs that people seem to think it is always the best tool for the job.

find /Users/brett/Development/repos/my-repo/ -name "*.php" |
  while IFS= read -r file; do grep -Iil 'mysql_query(' "$file" && label 2 "$file"

This command will find the .php files, save each of them as $file, run grep on them and if the grep matches, it will pass them to your function. I can't test this since I don't have a Mac but it should work perfectly well.

share|improve this answer

You can't use a function outside the shell instance(s) where it is defined. Since this function is in .bash_profile, it is available only in login shells, not in shells started in an X terminal (except on OSX which starts login shells in Terminal) nor in shells running scripts from files or from their command line. Functions cannot be invoked by other programs such as xargs.

While there are workarounds based on invoking the shell to start the function, the simplest solution is to put the code of your function in a script. That way it can be invoked from anywhere.

Not all functions can be standalone scripts, because standalone scripts cannot affect their parent shell (they can't see non-exported variables, they can't set any variable in the parent, etc.). Here, your function doesn't do anything that requires running inside the parent shell, so you might as well make it a script instead.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.