1

I already have an alias to (more) quickly search files :

alias f='find . -iname'

I use it as such:

$ f *statis*
./main/statistics.py
./test/test_statistics.py

Now, I would like to have another alias that does the same search but, instead of printing out the found files, will open them in vim. Ideally, it would work when multiple files are found.

I tried (using 'echo' instead of 'vim' for debugging purposes) :

 alias fvi='find . -exec echo {} + -iname'

...but it seems that -exec cancels the -iname coming afterwards:

$ fvi *statis*
 ./main/statistics.py ./main/probability.py ./test/test_statistics.py 
 ./test/test_probability.py
6

Since the -exec {} arguments must come after the -iname (since find 'executes' its arguments from left to right), you can't do what you want using an alias. Instead let your alias invoke a script containing for instance:

#!/bin/sh
find . -iname "$1" -exec vi {} \;

Note that this will invoke vi once for each file found. If there are many such files, you'll be doing many :q!'s or ZZ's to get out of them. If you want to invoke one instance of vi to edit all files found, change the \; to a +:

find . -iname "$1" -exec vi {} +

Alternatively, you could use command substitution to provide the arguments to vi:

vi $(find . -iname "$1")   # do not use when file names may contain whitespace

However the downside to this is that it will fail on file names containing whitespace.

If you prefer not to create a script file for the command, instead put the statement in a shell function:

fvi () { find . -iname "$1" -exec vi {} + ; }
  • 2
    I was just about to post an answer very similar to this. The only difference is that I was going to suggest implementing it as a shell function and I’d terminate the -exec with + (like the OP) rather than \; to avoid unnecessary process forks. That would result in only one instance of Vim being started. – Anthony G - justice for Monica Sep 7 '15 at 9:10
  • @AnthonyGeoghegan good point, and another alternative. Will add to answer. – zwets Sep 7 '15 at 9:12
  • 3
    Upvoted this already, however a little nitpickery about an edge case that is probably not even worth to be covered in the answer, but the second method will fail on filenames containing newlines; in case someone needs to avoid this they might use find . -iname "$1" -print0 | xargs -0 -I file vi file instead – kos Sep 7 '15 at 11:04
  • Great answer, thanks. A shell function will do the trick fine. – Manur Sep 7 '15 at 13:52
  • 1
    The command substitution forms will break with filenames containing any whitespace - you shouldn't even suggest them. – muru Sep 7 '15 at 13:58
3

... or use a dirty hack to use alias as if it took parameters ...

As several answers have pointed out, aliases do not support parameters the way shell scripts and functions do. Invoking an alias amounts to expanding the alias to its value, then executing the resulting command line with all arguments still in place.

No parameter substitution takes place. If you want parameter substitution, define a function instead of an alias. It's just as many keystrokes:

fvi () { find . -iname "$1" -exec vi {} + ; }

However, if you insist, here is a hack to refer to command line arguments inside an alias expansion: grab them from the shell history. In your case, this will do the job:

alias fvi='find . -iname "$(history|tail -n1|sed -e "s/^.*\sfvi\s*//")" -exec vi {} + #'

The output of the subshell executing history | tail -n1 | sed -e "s/.*\sfvi\s*//" is whatever follows fvi. This gets spliced into the find . -iname HERE -exec vi {} + command, which is what you need.

Except ... there is that queer hash sign at the end of the alias definition. I leave it to the reader to figure out its raison d'être, for the smile that unveiling a full-on hack brings. ;-)

1

If you really need an alias, than you could use this answer.


An alias in the bash doesn't accept parameters. Therefore you need a function and an alias and a slightly changed find command:

  1. Edit your .bashrc

    nano ~/.bashrc
    

    and add the lines below at the end of the file

    myfvi() {
        find . -type f -iname "$1" -exec vi -o {} +
    }
    alias fvi=myfvi
    
  2. Reload the configuration or logout and re-login

    source ~./bashrc
    
  3. Start with

    fvi '*statis*'
    

    But you could also use the function directly

    myfvi '*statis*'
    

Example

I have three files in my folder

$ ls -laog
total 4288
drwxrwxr-x  2 4329472 Sep  7 11:43 .
drwx------ 67   20480 Sep  7 11:28 ..
-rw-rw-r--  1       0 Sep  7 11:43 bar
-rw-rw-r--  1       4 Sep  7 11:23 foo
-rw-rw-r--  1       4 Sep  7 11:23 foobar

And when I use the alias

fvi 'foo*'

vi opens with two files.

enter image description here

  • 3
    I dont think alias even necessary. The user should be able to call function directly – Sergiy Kolodyazhnyy Sep 7 '15 at 9:51
  • 1
    @Serg Sure, but OP asked for an alias. – A.B. Sep 7 '15 at 9:51
  • 4
    But then why not call the shell function fvi? I don't see the point. – zwets Sep 7 '15 at 10:36
  • @zwets No, but you have my +1 =) – A.B. Sep 7 '15 at 11:40
  • That's what the OP asked for! :D – Fabby Sep 7 '15 at 21:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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