21

My .bashrc file contains a line to this effect:

alias prog="/path/to/script.sh $(find $(pwd) -name prog)"

When I comment out this line, Bash starts almost instantly when I open a new terminal. With this line, there is a 4-5 second delay before my cursor shows up.

Removing the nested commands $(pwd), etc. speeds it up again as well. Why is this happening? Can I still use nested commands somehow?

Peter Mortensen
  • 12,090
  • 23
  • 70
  • 90
BBales
  • 313
  • 1
  • 2
  • 5
  • 4
    The problem is the `find` command, which is execute at boot time and can take a long time to execute, depending on the directory structure. If you use single- instead of double-quotes, `find` will be executed at run time, when the `alias` is invoked. It depends on which working directory you want to use, that current at declaration time, or at run time. By the way `$(pwd)` is a rather inefficient way to express `.` or `$PWD`. – AFH May 14 '17 at 22:14
  • 15
    I know that's not what you are asking, but this looks a lot like a [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). Why do you need to locate the script using `find`? Once you installed it, you know where it is. Even if you update it frequently and change its name, you can maintain a symbolic link to it so it's always available under a fixed name. – sleske May 15 '17 at 07:41
  • 5
    @AFH Please post answers as answers, not comments. – David Richerby May 15 '17 at 11:31
  • 1
    @DavidRicherby - I wanted to make sure that this was indeed the answer before posting. I was puzzled that the script would work on files found within an arbitrary directory. – AFH May 15 '17 at 14:13

1 Answers1

48

Because the command substitution is inside double-quotes, it is evaluated at the time that the command is defined. This causes find to look through your hard disk contents while .bashrc is running.

You, by contrast, appear to want it evaluated at the time of use. In that case, use single quotes:

alias prog='/path/to/script.sh $(find "$(pwd)" -name prog)'

Note that this alias will fail if any of the files found have whitespace in their names. To avoid that:

alias prog='find . -name prog -exec /path/to/script.sh {} +'

This latter form will work reliably for any kind of file name.

John1024
  • 16,593
  • 5
  • 50
  • 45
  • 1
    'time of use'. And your second line avoids spawning a subshell. – rleir May 15 '17 at 03:57
  • 11
    On the downside, now every time you type `prog`, `find` would need to be run, whereas before, it would be run only once (on shell startup). – el.pescado - нет войне May 15 '17 at 06:21
  • Then again, owing to file caching, the second time you run the same `find` it's usually much faster. – reinierpost May 15 '17 at 08:53
  • 22
    @el.pescado On the upside, it's hard to imagine that the intended behaviour is to run the command on the files that existed at the time the user logged in, rather than the files that exist when they executed the command to process them. – David Richerby May 15 '17 at 11:33
  • 2
    @DavidRicherby Maybe we can cache the path of `prog` and re-run `find` if the old path no longer exists? – Alex Vong May 15 '17 at 20:17