I would like to have shell aliases that effectively are folder-aware, so that when running a command in a folder containing a .php
file, the contents of which are just 8.1
for example, the corresponding binary is run.
alias php8.0='/opt/homebrew/Cellar/[email protected]/8.0.26/bin/php'
alias php8.1='/opt/homebrew/Cellar/php/8.1.13/bin/php'
alias phpv='php"$(cat .php)" -v'
The above however, when running phpv
returns an error of command not found php8.1
. Whereas running php8.1 -v
on its own works correctly.
CodePudding user response:
Generally, alias
is for simple text that shortens something you type often.
alias ll=`ls -l`
If you're doing anything more complicated that that, use a function, not an alias.
As an exercise, to keep it close to your otiginal idea - set whichever you prefer as the default in your PATH, but when you want a structure to override it, then instead of a local hidden file with a number that gets hack/parsed on the fly, create a local symlink to the one needed in that folder. While it's a security concern, you could just set the local directory in your path and be done. A function can lessen that security concern by localizing that change to the scope of the specific function call.
php() { [[ -L ./php ]] && local PATH=".:$PATH"; # only localize if local symlink exists
local php=$(which php --skip-alias --skip-functions); # variable gets PATH-relevant version
if [[ -x "$php" ]] # checks for relevant success
then "$php" "$@" # runs appropriate version
else "No PHP available." # reports if none
fi
}
This falls down when you start needing entire subdirectory structures that need one version or the other, because now you have to put that symlink (or .php file, or whatever) in every folder in that structure, and it's a mess and a maintenance nightmare.
A better solution would be to set up as clean a structure as possible, and try to put (only) the highest/shortest directory paths at the top of all projects and miscellaneous errata that need alternate versions into a lookup.
phpv() {
local php='php'
local -A altv=(
[/first/dir/to/edit]="/opt/homebrew/Cellar/[email protected]/8.0.26/bin/php"
[/next/dir]="/some/other/version/bin/php"
[/next/dir/for/edits]="/opt/homebrew/Cellar/[email protected]/8.0.26/bin/php"
)
d="$PWD" # set longest path to check
while [[ -n "$d" ]]
do if [[ -n "${altv[$PWD]}" ]] # if there's an override
then php="${altv[$PWD]}" # override the varible
break # get out, using the longest match
fi
d=${d%/*} # check one directory higher for an override
done
$php" "$@" # runs appropriate version
}
This way, if you run phpv -v
(or with any other set of arguments) it should check where you are the list of places that get overrides, using the longest match, which allows different overrides in subdirectories, but only requires an override to list the highest, shortest paths that need to use an alternate version. If no overrides are found for your current directory or any parent, then you default to whatever is set in your PATH.
Using the example paths I included, if you are in /usr/bin
or /etc/
or /first/dir/to/delete
or anywhere else that exactly doesn't SOMEWHERE along its parentage, it will default to your PATH. If you are in /first/dir/to/edit/today
it will match /first/dir/to/edit
as a parent (any subdir of that path will) and use /opt/homebrew/Cellar/[email protected]/8.0.26/bin/php
. If you are in /next/dir/for/lunch
it will match /next/dir
as a parent and use /some/other/version/bin/php
, but in
/next/dir/for/edits
it matches the longer path first and uses /opt/homebrew/Cellar/[email protected]/8.0.26/bin/php
instead.
Hope all that helps inspire a useful solution.