6

I'm new to bash functions but was just starting to write some bits and pieces to speed up my work flow. I like to test this as I go along so I've found myself editing and sourcing my ~/.profile a lot and find ~/. a bit awkward to type...

So the first thing I thought I'd do was the following:

sourceProfile(){
    source ~/.profile
}

editProfile(){
    vim ~/.profile && sourceProfile
}

when running editProfile I'm getting an issue on the sourceProfile call. Initially I was getting the error:

-bash: ~./profile: No such file or directory

Note the lack of typo in my function!

However it works if I use an alias instead.

alias sourceProfile='source ~/.profile'

However after adding that alias and then commenting it out and uncommenting the function I start getting a syntax error instead:

-bash: /home/jonathanramsden/.profile: line 45: syntax error near unexpected token `('
-bash: /home/jonathanramsden/.profile: line 45: `sourceProfile(){'

the proceeding line is:

alias sservice='sudo service'

I'm pretty sure all I did was comment/uncomment! And based on my googling it seems like that's the syntax for defining functions.

JonnyRaa
  • 163

2 Answers2

5

Aliases are like some form of macro expansion, similar to the pre-preprocessing done in C with #define except that in shells, there's no clear and obvious delimitation between the pre-processing stage and the interpretation stage (also, aliases are not expanded in all contexts and there can be several rounds of alias expansion like with nested aliases).

When you do:

alias sourceProfile='source ~/.profile'
sourceProfile() {
  something
}

The alias expansion turns it into:

source ~/.profile() {
  something
}

which is a syntax error. And:

alias sourceProfile='source ~/.profile'
editProfile(){
  vim ~/.profile && sourceProfile
}

Turns it into:

editProfile(){
  vim ~/.profile && source ~/.profile
}

So, if you later redefine sourceProfile as a function, editProfile will not call it, because the definition of the editProfile has the expanded value of original alias.

Also, for functions (or any compound command), aliases are only expanded at function definition time (while they're read and parsed), not at run time. So this:

editProfile(){
  vim ~/.profile && sourceProfile
}
alias sourceProfile='source ~/.profile'
editProfile

won't work because sourceProfile was not defined at the time the body of the editProfile function was parsed, and there won't be any alias expansion at the time of running the editProfile function.

So, avoid mixing aliases and functions. And be wary of the implications of using aliases as they're not really commands but some form of macro expansion.

1

When development-testing functions, make sure that you reload (source) the function definition between each edit, or the older function definition will still be active. There is no typo in your function, and you should not get that error message (I can't reproduce it here), which means you're not running the function as it is written.

Also, I'd suggest that you start using $HOME rather than ~ when writing scripts, mostly because ~ does not at all behave like a variable (see Why doesn't the tilde (~) expand inside double quotes?).


Suggestion:

edit_profile () {
    local EDITOR=${EDITOR:-vim}
    local file="$HOME/.profile"

    "$EDITOR" "$file" && source "$file"
}

The file variable is extra, but the EDITOR variable may already be set to a sensible editor. If not, the code sets it to vim.

Kusalananda
  • 333,661
  • Thanks for the response! just to clarify that, do I need to type source editProfile rather than just sourcing the file that contains them? – JonnyRaa Oct 05 '17 at 10:02
  • @JonnyLeeds You should source the file that contains them. – Kusalananda Oct 05 '17 at 10:03
  • Hmm I've got a fresh terminal up and the file just works! Possibly I had a bad version of sourceProfile at some point. The series of errors still doesn't really make sense to me though – JonnyRaa Oct 05 '17 at 10:19
  • @JonnyLeeds It was probably some interaction between the older function in your shell environment and the alias with the same name. – Kusalananda Oct 05 '17 at 13:07