If we try to implement our mkcd alias attempt from the previous section in functions, we meet with more success than our attempt with aliases. Here's one possible implementation:
bash$ mkcd() { mkdir -p -- "$1" && cd -- "$1" ; }
This function works as we wanted, ensuring the directory is created before we try to change into it:
bash$ pwd /home/bashuser bash$ mkcd createme bash$ pwd /home/bashuser/createme
Note that this mkcd function runs more than one command in its body: a mkdir call, and a cd call. It also includes the "$1" string, which expands to the value of the first positional parameter passed to the function. We can see this in action with set -x:
bash$ set -x bash$ mkcd createme + mkcd createme + mkdir -p -- createme + cd -- createme bash$ set +x
We separate mkdir and cd with &&, because we only want to change into the directory if it was successfully created: that is, we run the cd command only if the mkdir command exited successfully.
Note also how the argument we provided to mkcd, the createme directory name, was passed to both the mkdir command and to the cd command afterward, each time via the "$1" parameter.
Finally, note that we put $1 in double quotes to stop any special characters in its value being interpreted by Bash, per the discussion of quoting behavior in Chapter 2, Bash Command Structure. This allows us to apply mkcd to any directory name we want:
bash$ mkcd 'My Book' bash$ mkcd '!@#$%^&*()' bash$ mkcd \'
After "$1", we can get the second positional parameter with "$2", the third with "$3", and so on. This can go beyond "$9" if you want, with curly brackets: "${10}", "${11}", and so on, but you should not need to index arguments that far very often.