How to create and use custom shell commands?

Article autor
September 9, 2025
How to create and use custom shell commands?
Elixir Newsletter
Join Elixir newsletter

Subscribe to receive Elixir news to your inbox every two weeks.

Oops! Something went wrong while submitting the form.

Table of contents

Each of us had a situation, where we had to invoke a few, same commands each time. Making it once is not that problematic, but when we are supposed to repeat given operations, it may be better just to create one function that will handle it all.

Create own functions

To create our own functions, firstly we need to open a new terminal. By default, we ought to be in the root directory (~), but to be sure you can execute the following command:

cd ~

and hit enter.

Right now, we can create a new file, in which we will store our function with commands. To do it, execute this:

touch .custom_bash_commands.sh

The naming convention is up to you, in this case, the file will be named .custom_bash_commands.sh , where '.' at the beginning means it is a hidden file. To see all of the hidden and visible files, you can just do ls -a.

Once we have created the file, we can open it. To do so, you can use VIM or your favorite text editor. I will be using Visual Studio Code. For that, I will execute the following command in my current directory:

open -a 'Visual Studio Code' .custom_bash_commands.sh

Now, we can create our function by following:

#!/bin/bash

function mix_all(){
  echo "mix format"
  mix format
  echo "mix static.credo"
  mix static.credo
  echo "mix dialyzer"
  mix dialyzer
  echo "mix test"
  mix test
}

The first line is just a convention, which is used while creating Scripts. Next, we have function declaration, which is called mix_all .

We use echo command to print out the following state. Of course, this is just a sample function, you can use whatever you want to up here.

Remember about saving the file now!

Source it and use it!

The next step is to source it into Bash/ZSH main file here. Why? Right now, the function is already created and can be used everywhere on our computer (but, in the following example, we have to have installed all needed dependencies in our project).

If you source it by executing:

source ~/.custom_bash_commands.sh

and invoke the function name:

mix_all

You will be prompted with the output of commands inside our mix_all , each by each.

But, it will be only available for the given directory and current session. If you will try to open a new terminal tab in the same directory and execute the function again, it will fail.

To omit that, let's come back to the root directory and open the .zshrc or .bashrc file (the file is dependent on your current OS version). In my case, I am going to open the .zshrc file:

open -a 'Visual Studio Code' .zshrc

And to make things work, we just need to source the previously created file here:

source ~/.custom_bash_commands.sh

And that's that. Right now we instruct our terminal to load our file on each terminal session. You can obtain your own command from any place you want to, without sourcing it.

Another example

The following function is just a really basic example. Let's create one more function, that will hold other operations. In the root directory, I am going to open the file, which I created at the very beginning. Inside of file, I am going to create another function:

#!/bin/bash

function mix_all(){
  # Previously created function
}

function create_user(){
  echo "User creation function"
  sudo dscl . -create /Users/$1
  sudo dscl . -create /Users/$1 UserShell /bin/bash
  sudo dscl . -create /Users/$1 RealName $2
  sudo dscl . -create /Users/$1 UniqueID $3
  sudo dscl . -create /Users/$1 PrimaryGroupID 1000
  sudo dscl . -create /Users/username NFSHomeDirectory /Local/Users/$1
  sudo dscl . -passwd /Users/username $4
  if dscl . list /Users | grep $1 ;
  then
    echo "User has been created!"
  else
    echo "Failed."
  fi
}

This function will allow us to omit 7 commands of user creation, for just one. The numbers prepend with a dollar sign are variables (eg. $1), and each of them stores a given value. The only things we need to remember are the name of our function and the order of passed arguments.

We do not have to source it now, because we have already done it previously. Just remember about saving the file! In our example, the order is:

function_name user_name users_real_name unique_user_id user_password

Just be sure, that unique_user_id is unique.

To execute the following function and create a user, let's move back to the terminal and just execute:

create_user curiosum Curiosum 1001 JustStayCuorius!

And that's that! For now, the user creation operation is automated. It is just a basic function for that usage, we could handle more sophisticated things here, such as error handler, or password validator.

Summary

In a very undemanding and fast way, we were able to omit invoking four and seven commands for just one function. The following code is just an example, and you can use your own created functions in many more ways! Bash is userfriendly, and helps us a lot in automating our workflow. It's good to get to know it well!

Related posts

Dive deeper into this topic with these related posts

No items found.

You might also like

Discover more content from this category

Manually update Apollo cache after GraphQL mutation

Ensuring that GraphQL mutations properly update your Apollo client's cache can be a bit tricky - here's how to manually control that.

How to check if an Elixir map has a given key in a guard?

Today's Advent of Code puzzle inspired me to create this TIL. It may sound trivial, but in fact, it's tricky if you are unfamiliar with the nuances of guards' functioning.

Load CSS as string using JS & Webpack import prefixes

People will tell you it's an antipattern, but what if a library needs you to do this?