Bash-it / bash-it

A community Bash framework.
MIT License
14.26k stars 2.29k forks source link

Invoking bash without #!/usr/bin/env #1491

Closed davidpfarrell closed 3 years ago

davidpfarrell commented 4 years ago

While looking at current PR #1490 I saw the the author switched the completion script:

- #!/usr/bin/env bash
+ #!/usr/bin/bash

This seemed like an oversight so I called it out on the PR, but it got me wondering how the rest of the repo is doing in this regard :

grep

$ find . -type f | grep -v '^./.git' | xargs -n1 grep -nH '#!' | grep ':1:' | grep -v '#!/usr/bin/env '

results (formatted)

# Plugins
todo.plugin.bash : #!/bin/bash

# Completions
git_flow_avh.completion.bash   : #!bash
wpscan.completion.bash         : #!/usr/bin/bash
docker-compose.completion.bash : #!/bin/bash
flutter.completion.bash        : #!/usr/bin/bash
sqlmap.completion.bash         : #!/bin/bash
bundler.completion.bash        : #! bash
laravel.completion.bash        : #!/usr/bin/bash
grunt.completion.bash          : #!/bin/bash
vagrant.completion.bash        : #!/bin/bash
gulp.completion.bash           : #!/bin/bash
lerna.completion.bash          : #!/bin/bash
vuejs.completion.bash          : #!/usr/bin/bash
virtualbox.completion.bash     : #!/usr/bin/bash
git_flow.completion.bash       : #!bash

# Scripts
reloader.bash : #!/bin/bash

# Aliases
curl.aliases.bash    : #!/bin/bash
msys2.aliases.bash   : #!/bin/bash
kubectl.aliases.bash : #!/bin/bash
apt.aliases.bash     : #!/bin/bash

# Themes
nwinkler_random_colors/nwinkler_random_colors.theme.bash : #!/bin/bash

@nwinkler interested in your thoughts here?

If we consider these wrong, I'm happy to put together a PR to set them all to #!/usr/bin/env bash

-DF

jpmcb commented 4 years ago

From what I've read, seems like using #!/usr/bin/env bash is the most flexible & system agnostic. And since bash-it is used in various systems and environments, maybe the best thing would be to have env find it for us. I'll go ahead and update my PR - thanks for this!!

nwinkler commented 4 years ago

Thanks for reviewing this - it would be great to get this in a consistent style - please go ahead with a PR.

Having said that, for the Bash-it plugins/completions/aliases/themes, it's less relevant, since they're all loaded using the source command anyway, which means that the shebang line in the individual files is pretty much ignored anyway... Still nice if we can get a uniform way of doing this.

There's a lot more cleanup work that could be done, I have a list of areas that should be looked at. Maybe it's time to start tackling that.

ravenhall commented 4 years ago

If the shebang line isn't necessary, my vote would be to remove it from all of them. Why maintain it if it isn't needed? Perhaps replace it with a comment along the lines of: # loaded by bash-it via source

nwinkler commented 4 years ago

Good point. Since it does not seem to be in all files, we probably should remove it from the other ones. The ones where we need it are bash_it.sh, install.sh and uninstall.sh.

davidpfarrell commented 4 years ago

The ones where we need it are bash_it.sh, install.sh and uninstall.sh.

@nwinkler Are you saying that, throughout the entire repository, these are the only files that actually need a #!? i.e. every .bash file is sourced as needed?

Assuming Yes:

That's great ! With that I lean even more toward removing leading #! lines from all .bash files.

Additionally, if we have any CI checks in place, we could add a check to enforce this rule.

Moreover, we could also add a check to enforce that .bash files do not have their executable flags set.

nwinkler commented 4 years ago

@davidpfarrell Yes, that should be right. If you take a look at the bash_it.sh file, it sources all of the other files.

I'm not entirely sure about the bats tests, they use the bats load command, but I assume that that uses source as well for loading files. The test/run script needs to be executable and requires a shebang, in addition to the ones listed above.

I don't think that we have any CI checks in place.

cornfeedhobo commented 4 years ago

Adding a comment instead of a shebang sounds like a pretty good idea.

You might even use the shellcheck ignore directive instead...

# shellcheck shell=bash disable=SC2148
NoahGorny commented 3 years ago

I think the best approach is to keep the shebang and rename all to /usr/bin/env bash, this is more formalized and indicative for new users IMO

cornfeedhobo commented 3 years ago

@NoahGorny I would agree if it weren't for our filename scheme that includes .bash. So, here is my proposal for a tie breaker, plus it would get something done that I've wanted for a while: base the decision on impact to load time - Let's benchmark it!

We can use a minimal alpine + bash container and setup a minimal environment where we could do something simple, like start 100 shells and calculate an average load time. It would be best to structure the test in a way that we could run it multiple times, allowing for the enabling of plugins and any associated software to locally benchmark a new plugin.

NoahGorny commented 3 years ago

@NoahGorny I would agree if it weren't for our filename scheme that includes .bash. So, here is my proposal for a tie breaker, plus it would get something done that I've wanted for a while: base the decision on impact to load time - Let's benchmark it!

We can use a minimal alpine + bash container and setup a minimal environment where we could do something simple, like start 100 shells and calculate an average load time. It would be best to structure the test in a way that we could run it multiple times, allowing for the enabling of plugins and any associated software to locally benchmark a new plugin.

Benchmarking is a good idea, but how it is connected to the shebang?

cornfeedhobo commented 3 years ago

@NoahGorny The more I dig into bash's internal mechanics, the more I learn that there are very small ways that increase computation cost, and they add up. Admittedly, the number of files we end up loading is extremely small compared the this benchmark, but it will illustrate what I was considering in my reply.

#!/usr/bin/env bash

cat > shebang.bash <<-EOF
    #!/usr/bin/env bash

    :
EOF

cat > nobang.bash <<-EOF
    :
EOF

trap 'rm -f shebang.bash nobang.bash' EXIT

time for i in {1..100000}; do source shebang.bash; done
time for i in {1..100000}; do source nobang.bash; done
$ ./benchmark.sh 

real    0m2.083s
user    0m1.259s
sys     0m0.811s

real    0m1.953s
user    0m1.158s
sys     0m0.776s
davidpfarrell commented 3 years ago

Hi Team!

Looks a benchmarking discussion broke out in my bash-headers discussion :)

You might want to start a new issue/discussion and move the comments there.

On a side note, though, seeing the notifications here reminded me to follow-up on this bash-header discussion here.

I have created PR #1765 which I hope addresses the concerns discussed here.

Cheers!

davidpfarrell commented 3 years ago

cornfeedhobo wrote:

Sorry, I don't see benchmarking as unrelated, nor do I see a consensus about how to move forward, but I guess we can continue the discussion in your pr...

@cornfeedhobo Sorry I think I may of misunderstood your benchmarking.

Were you saying that the presence of the #! line in a sourced file has a non-0 impact on its load/processing time?

If so, then I think that makes a strong case to remove #! headers from .bash files.

cornfeedhobo commented 3 years ago

@davidpfarrell Yeah, that is what I was trying to convey, but I think your use of echo run from bash: . has greater value.