PATH

Normally, when you login to a Linux system, you are given a login shell. A login shell is a fully interactive shell that does some cool stuff for you: it sets the PS1 variable (which determines how your prompt looks), correctly sets your PATH, and so on. Now, as you might imagine, there is also something other than a login shell. Technically, there are two dimensions that make up four different kinds of shells:

 Login

 Non-login

 Interactive

 Interactive login shell

 Interactive non-login shell

 Non-interactive

 Non-interactive login shell

 Non-interactive non-login shell


Most of the time, you'll use an interactive login shell, such as when you connect via (SSH) or directly via the Terminal console. The other often encountered shell is the non-interactive non-login shell, which is what is used when commands are run via at or cron. The other two are possible, but we will not be going into the details of when you would get those.

So, now that you know we get a different type of shell in at and cron, we're sure you'd like to know what the difference is (as in, why do you care about this?). There are a number of files that set your profile in Bash. Some of these are listed here:

  • /etc/profile
  • /etc/bash.bashrc
  • ~/.profile
  • ~/.bashrc

The first two, located in /etc/, are system-wide files, and are thus the same for all users. The latter two, which are found in your home directory, are personal; these can be edited to, for example, add aliases that you'd like to use. The alias command is used to create a shorthand for commands with flags. The ~/.bashrc file contains the line alias ll='ls -alF' by default on Ubuntu 18.04, which means you can type ll and have ls -alF executed instead.

Without going into too much detail (and oversimplifying quite a bit), an interactive login shell reads and parses all these files, while a non-interactive non-login shell does not (for more in-depth information, see the Further reading section). As always, a picture is worth a thousand words, so let's check out the differences ourselves:

reader@ubuntu:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
reader@ubuntu:~$ echo $PS1
[e]0;u@h: wa]${debian_chroot:+($debian_chroot)}[33[01;32m]u@h[33[00m]:[33[01;34m]w[33[00m]$
reader@ubuntu:~$ echo $0
-bash
reader@ubuntu:~$ at now
warning: commands will be executed using /bin/sh
at> echo $PATH
at> echo $PS1
at> echo $0
at> <EOT>
job 19 at Sat Dec 1 10:36:00 2018
You have mail in /var/mail/reader
reader@ubuntu:~$ tail -5 /var/mail/reader
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
$
sh

As we can see here, the values differ between a normal (SSH) shell and at executed commands. This goes for both PS1 and the shell itself (which we can find with $0). However, for at, the PATH is the same as for an interactive login session. Now, take a look at what happens if we do this in a crontab:

reader@ubuntu:~$ crontab -e
crontab: installing new crontab
reader@ubuntu:~$ crontab -l
# m h dom mon dow command
* * * * * echo $PATH; echo $PS1; echo $0
You have mail in /var/mail/reader
reader@ubuntu:~$ tail -4 /var/mail/reader
/usr/bin:/bin
$
/bin/sh
reader@ubuntu:~$ crontab -r # So we don't keep doing this every minute!

Starting off, PS1 is equal to what at sees. Since PS1 controls the way the shell looks, this is only interesting for interactive sessions; both at and cron are non-interactive. If we move on to PATH, we see a very different story: when running in cron, we get /usr/bin:/bin instead of /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin! Simply put, this means for all commands that are outside of /bin/ and /usr/bin/, we need to use the fully qualified filename. This even manifests itself in the $0 difference (sh versus /bin/sh). While this is not strictly necessary (since /bin/ is actually part of the PATH), it is still typical to see fully qualified paths for anything cron related.

Now, we have two options to deal with this, if we want to prevent errors such as sudo: command not found. We can either make sure we always use fully qualified paths for all commands (which, in practice, will definitely fail a few times), or we can make sure we set a PATH for the crontab. The first option gives us a lot more extra work for all things we'll ever do with cron. The second option is actually a really easy way to make sure we negate this problem. We can simply include a PATH=... at the top of the crontab, and all things executed by the crontab use that PATH. Give the following a try:

reader@ubuntu:~$ crontab -e
no crontab for reader - using an empty one
crontab: installing new crontab
reader@ubuntu:~$ crontab -l
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
# m h dom mon dow command
* * * * * echo $PATH
reader@ubuntu:~$
You have new mail in /var/mail/reader
reader@ubuntu:~$ crontab -r
reader@ubuntu:~$ tail -2 /var/mail/reader
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

Easy-peasy. If you want to verify this for yourself, you could keep the default PATH and run something from /sbin/ (such as the blkid command, which shows information on your disks/partitions). Since this isn't on the PATH, if you do not run it fully qualified, you'll encounter the error /bin/sh: 1: blkid: not found in your local mail. Pick any command that you could normally run and try it!

With this simple addition to a crontab, you can save yourself a lot of time and effort troubleshooting errors. As with all things in scheduling, you often have to wait at least a few minutes for each script attempt to run, making troubleshooting a time-intensive practice. Do yourself a favor and always make sure to include a relevant PATH as the first line of your crontab.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.220.202.209