How do I run ESLint from a saved Bash variable? - bash

I am setting up a project initialization script and a git pre-commit hook for work on a project. We have the scripts I want to run for linting not in the root directory but in a sub-directory and I would like to keep it that way.
What I want to be able to do is to set the full relative path to the binary executables for eslint and phpcs to bash variables then be able to run them. I also want to be able to execute the composer.phar binary from the bash variables.
So here is what I did.
# Set tool paths
PHPCS_PATH=`./wp-content/themes/our-theme/vendor/bin/phpcs`
PHPCBF_PATH=`./wp-content/themes/our-theme/vendor/bin/phpcbf`
ESLINT_PATH=`./wp-content/themes/our-theme/node_modules/.bin/eslint`
SASSLINT_PATH=`./wp-content/themes/our-theme/node_modules/.bin/sass-lint`
COMPOSER_PATH=`./wp-content/themes/our-theme/composer.phar`
I was trying to test these paths locally from the project root directory and I keep getting errors.
I copy and paste one of those lines into my terminal, hit enter, then do one of the following:
${ESLINT_PATH} and command ${ESLINT_PATH} and "${ESLINT_PATH}" and $ESLINT_PATH all yield me...
zsh: command too long: eslint [options] file.js [file.js] [dir]\n\nBasic configuration...
eval "${ESLINT_PATH}" and eval $ESLINT_PATH and eval "$ESLINT_PATH" all yield me...
zsh: no matches found: [options]
zsh: command not found: Basic
zsh: command not found: --no-eslintrc
zsh: command not found: -c,
zsh: no matches found: [String]
Am I losing my mind? How in the world do I make the path executable? If I take the contents of the path and run it, it works just fine.
Example: ./wp-content/themes/swmaster/node_modules/.bin/eslint actually tells me to specify a path.
What am I doing wrong here?

Looks like your issue is in these assignments:
# Set tool paths
PHPCS_PATH=`./wp-content/themes/our-theme/vendor/bin/phpcs`
PHPCBF_PATH=`./wp-content/themes/our-theme/vendor/bin/phpcbf`
ESLINT_PATH=`./wp-content/themes/our-theme/node_modules/.bin/eslint`
SASSLINT_PATH=`./wp-content/themes/our-theme/node_modules/.bin/sass-lint`
COMPOSER_PATH=`./wp-content/themes/our-theme/composer.phar`
Those back-ticks are command substitutions. An easier to read way of writing this is would be:
PHPCS_PATH=$(./wp-content/themes/our-theme/vendor/bin/phpcs)
...
I don't think that is what you really want. A command substitution actually executes what is inside and is substituted by whatever goes to stdout. I think you were actually trying to do string assignments. This can be accomplished by simply removing the back-ticks because there are no spaces in the paths. But it is a good habit to get into to just double quote them anyway. Try this:
# Set tool paths
PHPCS_PATH="./wp-content/themes/our-theme/vendor/bin/phpcs"
PHPCBF_PATH="./wp-content/themes/our-theme/vendor/bin/phpcbf"
ESLINT_PATH="./wp-content/themes/our-theme/node_modules/.bin/eslint"
SASSLINT_PATH="./wp-content/themes/our-theme/node_modules/.bin/sass-lint"
COMPOSER_PATH="./wp-content/themes/our-theme/composer.phar"
Another method to solve your issue would be to add these directories to your PATH variable. For example, if you set your PATH to include the bin directory for phpcs and phpcbf, you would be able to execute those programs without specifying a full (or relative in this situation) path:
export PATH=$PATH:./wp-content/themes/our-theme/vendor/bin
# or export PATH=$PATH:/full/path/to/wp-content/themes/our-theme/vendor/bin
# Now you can just run the line below without a path...
phpcs

This morning I found what I was looking for in this gist: https://gist.github.com/rashtay/328da46a99a9d7c746636df1cf769675#file-pre-commit-eslint
My solution is now:
# Set tool paths
PHPCS="$(git rev-parse --show-toplevel)/wp-content/themes/our-theme/vendor/bin/phpcs"
PHPCBF="$(git rev-parse --show-toplevel)/wp-content/themes/our-theme/vendor/bin/phpcbf"
ESLINT="$(git rev-parse --show-toplevel)/wp-content/themes/our-theme/node_modules/.bin/eslint"
SASSLINT="$(git rev-parse --show-toplevel)/wp-content/themes/our-theme/node_modules/.bin/sass-lint"
This works from any directory in the repo because it ties to the repo base path. It is dynamic in that way.

Related

How to remove the need of "./" in every shell script in MacOS?

I'm studying shellscript and I know that there is a way to skip "./" when you need to execute a shellscript.
For example: after I made a script like this:
echo "hello world!"
I use the command "chmod +X" to make it executable. But to execute it on my terminal I need to type:
./helloworld.sh
I know that theres is a way to skip this "./" if you're using bash. You go to .bashrc and write in the end of the script "PATH=PATH:."
But since I'm using MacOS, which use zsh, I tried to type "PATH=PATH:." in the end of my .zshrc but this didn't work.
Then I would like to know if there is a way to remove the need of "./" for every shellscript that I need to run.
Thank you people
P.S.: I have brew and ohmyzsh installed in my machine
What's Wrong with Your Code
The reason your example doesn't work is because PATH is a variable, and you need to expand it by prefixing it with the dollar sign to access its value, e.g. PATH=$PATH:. rather than just PATH=PATH:.. However, there are some other considerations too.
Prepending, Appending, and Exporting PATH
It's generally not recommended to treat your current working directory as part of your PATH for security reasons, but you can do it in any Bourne-like shell by prepending or appending . (which means any current working directory) to your PATH. Depending on where you call it and how you've initialized your shell, you may also need to export the PATH variable to your environment.
Some examples include:
# find the named executable in the current working directory first
export PATH=".:$PATH"
# find the named executable in the current working directory
# only if it isn't found elsewhere in your PATH
export PATH="$PATH:."
# append only the working directory you're currently in when you
# update the PATH variable, rather than *any* current working
# directory, to your PATH
export PATH="$PATH:$PWD"
Note that it's also generally a good idea to quote your variables, since spaces or other characters may cause problems when unquoted. For example, PATH=/tmp/foo bar:$PATH will either not work at all or not work as expected. So, wrap it up for safety (with quotes)!
Use Direnv for Project-Based PATH Changes
You might also consider using a utility like direnv that would enable you to add the current working directory to your PATH when you enter known-safe directories, and remove it from the PATH when leaving the directory. This is commonly used for development projects, including shell scripting ones.
For example, you could create the following ~/dev/foo/.envrc file that would only prepend the current working directory when in ~/dev/foo, and remove it again when you move above the current .envrc in your filesystem:
# ~/dev/foo/.envrc
#
# prepend "$HOME/dev/foo:$HOME/dev/foo/bin" to your
# existing PATH when entering your project directory,
# and remove it from your PATH when you exit from the
# project
PATH_add "$PWD/bin"
PATH_add "$PWD"
Because direnv uses whitelisting and ensures that your items are prepended to PATH, it's often a safer and less error-prone way to manage project-specific modifications to your PATH or other environment variables.
Use "$HOME/bin" to Consolidate Scripts
Another option is to create a directory for shell scripts in your home directory, and add that to your PATH. Then, any script placed there will be accessible from anywhere on your filesystem. For example:
# add this line to .profile, .zprofile, .zshrc, or
# whatever login script your particular terminal calls;
# on macOS, this should usually be .zprofile, but YMMV
export PATH="$HOME/bin:$PATH"
# make a ~/bin directory and place your
# executables there
mkdir -p ~/bin
cp helloworld.sh ~/bin/
Assuming the shell scripts in your bin directory already have their executable bit set (e.g. chmod 755 ~/bin/*sh), you can run any shell script in that directory from anywhere on your filesystem.
You need PATH=$PATH:. -- the $ to expand the (old) value of PATH is important.

How does "which" work in osx?

I'm trying to install a linter for sublime tex in OSX. It cannot be found in sublime. According to the docs, this is likely because the PATH is wrong. It says I should try this:
hash -r
which linter
but replace linter with the "linter executable". I tried
which standard
which sublimeLinter-contrib-standard
which fooBarBaz
but neither of them returns anything. Do I need to execute this in a particluar directory or is something else wrong?
which uses the value of PATH that it inherits. The fact that which returns nothing confirms that you need to add the appropriate directory to your PATH.
which command looks through the directories defined in your shell’s PATH variable, as well as any aliases you have defined in your ~/.bash_profile file, to find the location of the command given as an argument. This is useful when you want to find out exactly which version of a command is being used. Here’s an example:
$ which ls
/bin/ls
This tells you that when you use the ls command, it is /bin/ls that is run. This command will also tell you if a specific command is a shell builtin.

Terminal commands can not be found OSX

A majority of terminal commands don't work, for example .
ls
sudo
vi
with the error -bash: ls: command not found my path is echo $PATH
“/Users/username/usr/local/bin I get the feeling that “ should not be there but not sure how edit it.
What should the path be and how do I get the path to stay the same?
You need to add more paths to your $PATH variable. Try running whereis ls and check where is the binary of the command.
You can add more paths like this: export PATH=$PATH:NEW_PATH
I had a similar experience recently where a lot of my terminal commands were not being found despite being clearly saved in my bash_profile. After lengthy process of elimination I realised that the issue was caused when I tried to export a new path. The error that I had made was putting a space in the command. So I had to change
export SOMETHING = /path/to/something.apk to
export SOMETHING=/path/to/something.apk
So I would recommend you check all your path declarations to ensure you don't have any white spaces. Also don't forget to source your bash_profile or what ever type of command line shell you use.

cron: run a script that sources a function

I have script that does a bunch of stuff. It sources a bunch of functions that are in the directory the script is being run from. i.e.
/home/me/script.sh
/home/me/function1
/home/me/function2
If I cd into /home/me and run ./script.sh everything works fine. The functions are sourced and do what needs to be done.
However, if I try to run this as a cron job, it will run up until the point I am trying to source the functions, and then it just stops and the process is terminated (if I run it directly from the directory, at least I get some errors).
Like wise, if I try to run this from another directory, I get a bunch of errors. e.g.
cd /opt/
/home/me/script.sh
function1: command not found
function2: command not found
I'm sure this has something to do with environmental variables, but I have no idea which ones. I have tried setting (in crontab):
PATH=/home/me
SHELL=/bin/bash
But that doesn't work either. Any help is appreciated. I don't want to hard code in the paths to the functions, and instead make them relative to the path the script is in (preferably the same dir).
Please let me know if you need any more information.
You are most probably aware of this, but just to be clear: A shell function does not have a path. They just need to be loaded into the current shell by sourcing the script that contains them:
source /path/to/functions
or
cd /path/to/functions
source functions
If you are talking about shell programs (scripts) instead, then you need to account for the fact that on Unix-like OS, the current directory is never in the PATH by default:
/path/to/functions/function1
or
cd /path/to/functions
./function1
You tagged your question Bash, but note that to be POSIX-compatible (e.g. if using sh), you have to use the . keyword (instead of either . or source on Bash) and the same restrictions regarding the PATH as for command execution apply, see dot:
. ./function1

git ruby script not working "must be run in a work tree"

Want to copy the contents of the CWD repo (bare) into the '../deploy' folder. The git command below works just fine on the Bash command line (with manual variable substitution) but always errors out when called using backticks in ruby. What's the problem?
#!/usr/bin/env ruby
deploy_to_dir = File.expand_path('../deploy')
`GIT_WORK_TREE="#{deploy_to_dir}" git checkout -f master`
This line
File.expand_path('../deploy')
will give you a path relative to your cwd, not relative to the Ruby script. Instead, you should use
File.expand_path('../deploy', __FILE__)
Dumb mistake. The target directory was misspelled and I never noticed due to tab completion.

Resources