Make your own shell command
Define a shell function in a file, source it from your shell config, and call it like any built in command. Why chmod is not part of it and which names to avoid.
A shell function loaded at startup behaves exactly like ls or cd: you type
its name and it runs. There are three steps. Write the function in a file,
source that file so the current shell knows about it, and add the source line
to your shell config so every future shell knows too.
Write the function
Put it in a dotfile in your home directory. The name does not matter, only that you can remember it.
touch ~/.commands.sh# ~/.commands.sh
greet() {
echo "hello world"
}greet() { ... } and function greet { ... } both work in bash and zsh. The
first form is POSIX and works in more shells, so prefer it.
Load it
source ~/.commands.shsource reads the file in the shell you are already in, so everything it
defines is still there when it finishes. . is the same command with a shorter
name: . ~/.commands.sh.
This is also why chmod +x is not part of the process. The execute bit lets the
kernel run a file as a program, which starts a new shell to do it. That child
shell would define the function, run to the end, and exit, taking the function
with it. Sourcing avoids the child entirely, and a file you only ever source
never needs to be executable.
Make it permanent
Sourcing affects one shell. Close the terminal and the function is gone. To get it in every new shell, put the source line in your shell's startup file.
echo 'source ~/.commands.sh' >> ~/.zshrc # zsh
echo 'source ~/.commands.sh' >> ~/.bashrc # bashmacOS has used zsh as the default since Catalina, so ~/.zshrc is usually the
right one. Check with echo $SHELL if you are not sure.
Reload after an edit
New shells read the file on startup, so they are already current. The shell you edited in is not, and it keeps the old definition until you tell it otherwise.
source ~/.commands.shRun that after every change. Forgetting it is the usual reason an edit seems to have done nothing.
Do not shadow an existing command
Your function wins over anything already on the system with that name, which is
worth being careful about. test is a real POSIX builtin that scripts use for
conditionals, so a function called test quietly breaks other people's scripts
and some of your own shell's behaviour.
Check the name before you commit to it.
type greet
command -v greetIf either prints a path or a description, the name is taken. Silence or "not found" means it is free.
Function or alias
An alias substitutes text at the start of a command and nothing else. A function can take arguments, branch, and run several commands, so anything with logic wants to be a function.
alias ll='ls -lah'
mkcd() {
mkdir -p "$1" && cd "$1"
}Quote "$1" every time. Unquoted, a path with a space in it arrives as two
separate arguments and the command does the wrong thing.
When a script is the better answer
A function only exists inside shells that sourced it. Nothing else can see it: not cron, not another program, not a script running under a different shell.
When you need any of those, make it a real file on your PATH instead. This is
where chmod +x belongs, because now the file genuinely is being executed.
mv mytool ~/bin/mytool
chmod +x ~/bin/mytool
export PATH="$HOME/bin:$PATH" # add this line to ~/.zshrc as wellStart the file with a shebang, #!/usr/bin/env bash, so the system knows what
to run it with.