Table of Contents

Secure Ubuntu System - Initial Configuration

Login

Login with your previously created Administrator's username and password (e.g. administrator and adminpass).

Login using a SSH Client

ssh adminstrator@192.168.1.2

The terminal will show something like:

The authenticity of host '69.55.55.20 (69.55.55.20)' can't be established.
ECDSA key fingerprint is 79:95:46:1a:ab:37:11:8e:86:54:36:38:bb:3c:fa:c0.
Are you sure you want to continue connecting (yes/no)?

Go ahead and type yes, and then enter the password of the administrator, adminpass.


Get root privileges (Optional)

Because we must run all the next steps from this document with root privileges, we can either prepend all commands in this tutorial with the string sudo, or we become root right now by typing:

sudo -i

…and entering the Administrator's password, adminpass.

IMPORTANT: If this is done, then remember to remove the sudo command from the front of any future issued command.

DANGER: Do NOT use the following command:

sudo su

and do NOT enable the root login by running:

sudo passwd root

and giving root a password.

With these options one can log in as the root user, but this is frowned upon by the Ubuntu developers and community for various reasons.

If for some reason the root account has been enabled then disable it again, issuing the following command:

sudo passwd -dl root

Update APT Sources

Keeping the system updated is vital before starting anything on your system. This will prevent people using known vulnerabilities against your system.

Update the Linux Installation.

Edit the /etc/apt/sources.list file. Comment out or remove the installation CD from the file and make sure that the universe and multiverse repositories are enabled.

Issue the following command:

sudo vi /etc/apt/sources.list

It should look like this:

/etc/apt/sources.list
#
# deb cdrom:[Ubuntu-Server 15.04 _Vivid Vervet_ - Release amd64 (20150422)]/ vivid main restricted
# deb cdrom:[Ubuntu-Server 15.04 _Vivid Vervet_ - Release amd64 (20150422)]/ vivid main restricted
 
# See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to
# newer versions of the distribution.
deb http://gb.archive.ubuntu.com/ubuntu/ wily main restricted
deb-src http://gb.archive.ubuntu.com/ubuntu/ wily main restricted
 
## Major bug fix updates produced after the final release of the
## distribution.
deb http://gb.archive.ubuntu.com/ubuntu/ wily-updates main restricted
deb-src http://gb.archive.ubuntu.com/ubuntu/ wily-updates main restricted
 
## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
## team. Also, please note that software in universe WILL NOT receive any
## review or updates from the Ubuntu security team.
deb http://gb.archive.ubuntu.com/ubuntu/ wily universe
deb-src http://gb.archive.ubuntu.com/ubuntu/ wily universe
deb http://gb.archive.ubuntu.com/ubuntu/ wily-updates universe
deb-src http://gb.archive.ubuntu.com/ubuntu/ wily-updates universe
 
## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
## team, and may not be under a free licence. Please satisfy yourself as to
## your rights to use the software. Also, please note that software in
## multiverse WILL NOT receive any review or updates from the Ubuntu
## security team.
deb http://gb.archive.ubuntu.com/ubuntu/ wily multiverse
deb-src http://gb.archive.ubuntu.com/ubuntu/ wily multiverse
deb http://gb.archive.ubuntu.com/ubuntu/ wily-updates multiverse
deb-src http://gb.archive.ubuntu.com/ubuntu/ wily-updates multiverse
 
## N.B. software from this repository may not have been tested as
## extensively as that contained in the main release, although it includes
## newer versions of some applications which may provide useful features.
## Also, please note that software in backports WILL NOT receive any review
## or updates from the Ubuntu security team.
deb http://gb.archive.ubuntu.com/ubuntu/ wily-backports main restricted universe multiverse
deb-src http://gb.archive.ubuntu.com/ubuntu/ wily-backports main restricted universe multiverse
 
deb http://security.ubuntu.com/ubuntu wily-security main restricted
deb-src http://security.ubuntu.com/ubuntu wily-security main restricted
deb http://security.ubuntu.com/ubuntu wily-security universe
deb-src http://security.ubuntu.com/ubuntu wily-security universe
deb http://security.ubuntu.com/ubuntu wily-security multiverse
deb-src http://security.ubuntu.com/ubuntu wily-security multiverse
 
## Uncomment the following two lines to add software from Canonical's
## 'partner' repository.
## This software is not part of Ubuntu, but is offered by Canonical and the
## respective vendors as a service to Ubuntu users.
# deb http://archive.canonical.com/ubuntu vivid partner
# deb-src http://archive.canonical.com/ubuntu vivid partner

NOTE: The Ubuntu version and name may differ in the file, depending on what version of Ubuntu is being used.

Save the file, then issue the following command:

sudo aptitude update 

to update the apt package database and…

sudo aptitude safe-upgrade

to install the latest updates (if there are any). If you see that a new kernel gets installed as part of the updates, you should reboot the system afterwards:

sudo reboot 

aptitude safe-upgrade will not upgrade packages if:

  • relied dependencies have not been updated to the required version.
  • installing the upgrade means removing dependencies that other packages need.

References


Enable Automatic Security Updates (optional)

Enable automatic updates can be crucial for your server security. It is very important to stay up to date. If you cannot do the weekly maintenance. This is not a perfect solution because an administrator is not monitoring what is being updated and testing after updates.

You can install the unattended-upgrades by using this command:

sudo apt-get install unattended-upgrades 

To enable it, run:

sudo dpkg-reconfigure -plow unattended-upgrades 

This will create the file /etc/apt/apt.conf.d/20auto-upgrades with the following contents:

/etc/apt/apt.conf.d/20auto-upgrades
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";

Customize automatic updates

You can customize the automatic updates if you prefer. For example, you can get notifications when a security update is completed. To enable ONLY security updates, please change the code to look like this:

/etc/apt/apt.conf.d/20auto-upgrades
  // Automatically upgrade packages from these (origin:archive) pairs
  Unattended-Upgrade::Allowed-Origins {
      "${distro_id}:${distro_codename}-security";
  //  "${distro_id}:${distro_codename}-updates";
  //  "${distro_id}:${distro_codename}-proposed";
  //  "${distro_id}:${distro_codename}-backports";
  };

To get notification by email, update the following line with your email address:

/etc/apt/apt.conf.d/20auto-upgrades
Unattended-Upgrade::Mail "my_user@my_domain.com";

Reference


Upgrading Ubuntu Server to latest LTS version (optional)

Having the system upgraded to the most recent LTS version will help towards ensuring that known vulnerabilities against your system are kept to a minimum.

WARNING: If possible, don't use SSH when upgrading a server. SSH may get logged out and might be unable to login back into the system using SSH until it is fully upgraded. By logging directly into the server this will not be a problem.

Back up the Server First

This is a good option. The important thing is knowing for certain that you can restore/recreate the server in case the upgraded server is not left in a bootable, usable condition.


Install the Upgrade Manager

sudo aptitude -y install update-manager-core 

Double-check Configuration File

Run this command to check whether “/etc/update-manager/release-upgrades” has the line “Prompt=lts”.

/etc/update-manager/release-upgrades
[[ `grep Prompt=lts /etc/update-manager/release-upgrades` = 'Prompt=lts' ]] && echo '"/etc/update-manager/release-upgrades" is Ok' || echo 'Edit /etc/update-manager/release-upgrades and add line "Prompt=lts"' 

If the line is not present edit “/etc/update-manager/release-upgrades” with:

sudo vi /etc/update-manager/release-upgrades 

…and add the line:

/etc/update-manager/release-upgrades
Prompt=lts

Run the Upgrade Manager

sudo do-release-upgrade 

Follow the on-screen instructions.

When the upgrade manager encounters a configuration file with custom changes, a decision needs to be taken whether to keep the existing configuration file or to replace it with the new configuration file.

Usually it’s okay to retain the existing configuration files if you want the system to continue running as it has before. However, any new functionality may be missed by not having the most recent configuration files.

If you do decide to keep the existing files, then you may need to tweak the configuration file for:

  • MySQL - You may be prompted for a new MySQL root password at times. Just press Enter without entering a new password to keep the existing MySQL password.
  • phpMyAdmin - Adding a new line to phpMyAdmin's configuration file may be needed for the new phpMyAdmin version.

Reference


Update VIM

Issue the following command:

sudo aptitude install vim-nox

The default vi package installed on Debian and Ubuntu is vim-tiny, which is really restricted and only really appropriate for very small environments.

To update to the full vim package, install vim-nox. Of course, different text editor such as joe or nano can be installed as well.


Add Swap (optional)

Some pre-installed Ubuntu Server are not configured with SWAP. Linux swaps allow a system to harness more memory than was originally physically available.

Check for SWAP space

Check if a SWAP file exists and that it is enabled.

sudo swapon -s 

If there's no SWAP file, you should get a result like this:

Filename                                Type            Size    Used    Priority

Create and Enable the Swap File

For less then 1GB of physical memory (RAM), it's highly recommended that the swap space should, as a base minimum, be equal to the amount of RAM. Also, it's recommended that the swap space is maximum twice the amount of RAM depending upon the amount of hard disk space available for the system because of diminishing returns.

For more modern systems (>1GB), your swap space should be at a minimum minimum be equal to your physical memory (RAM) size “if you use hibernation”, otherwise you need a minimum of round(sqrt(RAM)) and a maximum of twice the amount of RAM. The only downside to having more swap space than you will actually use, is the disk space you will be reserving for it.

The “diminishing returns” means that if you need more swap space than twice your RAM size, you'd better add more RAM as Hard Disk Drive (HDD) access is about 10³ slower then RAM access, so something that would take 1 second, suddenly takes more then 15 minutes! And still more then a minute on a fast Solid State Drive (SSD)…

Before the SWAP file it created, determine how much swap is needed. Here's a quick guide to help you.

RAM in your ServerRecommended swap spaceRecommended swap space if allowing for hibernationMaximum swap space
256MB or less256MB512MB512MB
512MB512MB1024MB1024MB
1024MB1024MB2048MB2048MB
1GB1GB2GB2GB
2GB1GB3GB4GB
3GB2GB5GB6GB
4GB2GB6GB8GB
5GB2GB7GB10GB
6GB2GB8GB12GB
8GB3GB11GB16GB
12GB3GB15GB24GB
16GB4GB20GB32GB
24GB5GB29GB40GB
32GB6GB38GB64GB
64GB8GB72GB128GB
128GB11GB139GB256GB

To create the SWAP file, you will need to use the dd command:

sudo dd if=/dev/zero of=/swapfile1 bs=1024 count=512k 

All of this means:

RAM in your ServerRecommended swap space
if=/dev/zeroRead from the /dev/zero file. /dev/zero is a special file that provides as many null characters to build the storage file called /swapfile1.
of=/swapfile1Write to storage file /swapfile1.
bs=1024Read and write 1024 BYTES bytes at a time.
count=512kCopy only 524288 BLOCKS input blocks. This is the size of the swap file.

Prepare the swap file by creating a Linux swap area

sudo mkswap /swapfile1 

The results display:

Setting up swapspace version 1, size = 524284 KiB
no label, UUID=265d3e61-6e2b-4126-baba-6e6185e97b46

Activate the swap file

sudo swapon /swapfile1 

Confirm that the swap partition exists.

sudo swapon -s

This will output something like:

Filename                                Type            Size     Used    Priority 
/swapfile1                              file            524284    0           -1       

This will last until the server reboots. Before, rebooting the server. Let's create the entry in the fstab:

sudo vi /etc/fstab

and add the following line:

/etc/fstab
/swapfile1       none    swap    sw      0       0 

Improve performance

Swappiness in the file should be set to 0. Skipping this step may cause both poor performance, whereas setting it to 0 will cause swap to act as an emergency buffer, preventing out-of-memory crashes. You can do this with the following commands:

echo 0 | sudo tee /proc/sys/vm/swappiness
echo vm.swappiness = 0 | sudo tee -a /etc/sysctl.conf

A low swappiness value causes the kernel to avoid swapping, a higher value causes the kernel to try to use swap space.

Swappiness ValueStrategy
0The kernel will swap only to avoid an out of memory condition, when free memory will be below vm.min_free_kbytes limit. See the VM Sysctl documentation.
1Kernel version 3.5 and over, as well as Red Hat kernel version 2.6.32-303 and over: Minimum amount of swapping without disabling it entirely.
10This value is sometimes recommended to improve performance when sufficient memory exists in a system.
60The default value.
100The kernel will swap aggressively.

Secure SWAP

To prevent the file from being world-readable, you should set up the correct permissions on the swap file:

sudo chown root:root /swapfile1
sudo chmod 0600 /swapfile1

Reboot to make sure the new swap gets activated properly at start-up.


Change the Default Shell

Issue the following command:

sudo dpkg-reconfigure dash 

When asked “Install dash as /bin/sh?” specify “No”.

/bin/sh is a symlink to /bin/dash, however we need /bin/bash, not /bin/dash:

The reason that dash was set as the default is that dash provides faster boot times. It does not however have the full feature set offered by bash. On a modern server this speed difference in booting is negligible; and not too important as servers usually are not booted very often.


Synchronize the System Clock

It is a good idea to synchronize the system clock with an NTP (network time protocol) server over the Internet.

Issue the following command:

sudo aptitude install ntp ntpdate

Configure ntpd as necessary, by issuing the command:

sudo vi /etc/ntp.conf

Add or remove server lines as required:

/etc/ntp.conf
# Use servers from the NTP Pool Project. Approved by Ubuntu Technical Board
# on 2011-02-08 (LP: #104525). See http://www.pool.ntp.org/join.html for
# more information.
 
server 0.ubuntu.pool.ntp.org
server 1.ubuntu.pool.ntp.org
server 2.ubuntu.pool.ntp.org
server 3.ubuntu.pool.ntp.org

After changing the config file reload ntpd, by issuing the following command:

sudo /etc/init.d/ntp restart

Check the ntp status, by issuing the following command:

sudo ntpq -p

which should display something like:

     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
 ran.as65342.net 192.36.144.23    2 u   40   64    3   35.756   14.750   3.722
 orgin.sorch.inf 91.189.94.4      3 u   39   64    3   15.234   14.823   3.803
 portal.kt.kg    89.109.251.23    2 u   37   64    3  139.980   14.118   2.702
 i4DF67E84.pool. .PPSb.           1 u   38   64    3   37.265   16.166  91.399
 europium.canoni 131.188.3.220    2 u   39   64    3   15.170   14.873   4.720

ALERT: Ubuntu offers two ways of updating the time, i.e. ntpdate and ntpd. ntpdate is a bit of a blunt instrument - it adjusts the time in one big correction. The ntp daemon ntpd is far more subtle. It calculates the drift of your system clock and continuously adjusts it, so there are no large corrections that could lead to inconsistent logs for instance. The cost of using ntpd against ntpdate is a little processing power and memory, but for a modern server this is negligible, however ntpd runs as a service.

Note that for PCI-DSS compliance, we should not be running NTP as a service, unless this specific server is going to be used as a NTP server. The reason being that PCI-DSS stipulates that each server in the network should only run a single external service, and as NTP could be classified as a service, this same server could not then be used for any other service, such as MySql.

If we don't want this to run as a service, we should only use ntpdate.

Issue the following commands in this case:

sudo aptitude install ntpdate

and test by issuing the command:

sudo ntpdate pool.ntp.org

which should display something like:

22 Jun 00:06:43 ntpdate[3032]: adjust time server 87.106.21.237 offset 0.000174 sec

To use a different NTP Server such as pdc.sharewiz.net, modify the configuration file /etc/default/ntpdate if required:

NTPDATE_USE_NTP_CONF=no
NTPSERVERS="pdc.sharewiz.net"

and test again by issuing the command:

sudo ntpdate pdc.sharewiz.net

Create a cron job to regularly keep the system’s time in sync, by issuing the command:

sudo vi /etc/cron.hourly/ntpdate

and populate with the following contents:

/etc/cron.hourly/ntpdate
#!/bin/bash
#
# Calls ntpdate-debian to syncronize the time
 
ntpdate-debian

and finally make the cron job executable, by issuing the following command:

sudo chmod 755 /etc/cron.hourly/ntpdate

and your system time will always be in sync.

The cron job calls the ntpdate-debian function instead of simply the ntpdate function. The ntpdate function could be used, but the actual NTP server has to then be passed as a parameter.

ntpdate-debian does not need a parameter and uses the time-servers recorded within the /etc/default/ntpdate file.


Update crontab times

Issue the following command:

sudo vi /etc/crontab

and modify the contents as per the following:

/etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.
 
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
 
# m h dom mon dow user command
#17 * * * * root cd / && run-parts --report /etc/cron.hourly
#25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
#47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
#52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#
0 * * * * root cd / && run-parts --report /etc/cron.hourly
0 0 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
0 0 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
0 0 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#

For some strange reason, the default hour when the daily, weekly, and monthly cron jobs are run is around 6am in the morning.

The hour is modified to be close to midnight so that we can ensure that jobs are run at the start of a new day.

This also helps with log rotation, in that new daily logs are started at the beginning of each day instead of at 6am.

NOTE: Slight differences between the minutes of each individual cron job could ensure that jobs run by different parts of cron don’t conflict.


Add Global Aliases

Aliases simplify the running of complex commands. Arguments cannot be used in an alias command. If arguments are needed, a shell function should be used instead of an alias.

Global Aliases would normally be added to the /etc/profile file, but it’s cleaner to have a separate file for the aliases.

NOTE: A user can overwrite the global aliases if needed by defining their own aliases within their .bashrc, .bash_aliases, or .profile files within their own home directories.

To see what aliases are currently defined use the alias command. To disable an alias in your current shell, use unalias name. An alias can be temporarily disabled in the current command by prefixing the alias name with a \. For example: \ls.

Issue the following command:

sudo vi /etc/profile.d/bash_aliases.sh

and add the following to the file:

/etc/profile.d/bash_aliases.sh
# Instruct bash to expand the arguments to aliases.
shopt -s expand_aliases
 
#-------------------------------------------------------------
# Protection for these commands; which will prompt before overwriting.
#-------------------------------------------------------------
# Do not delete / and prompt before deleting.
alias rm='rm -i --preserve-root'
 
alias cp='cp -i'
alias mv='mv -i'
alias ln='ln -i'
 
# Preventing changing perms on /
alias chown='chown --preserve-root'
alias chmod='chmod --preserve-root'
alias chgrp='chgrp –preserve-root'
 
alias rmdir='rm -Rf $1'
 
#-------------------------------------------------------------
# cd
#-------------------------------------------------------------
# To pick up when user forgets the space.
alias cd..='cd ..'
 
# Uses cd() function = pushd, 
# b = go backwards (popd), f = go forwards (kind of like "unpopd").
alias d='dirs'
alias b='pushd +1'         # go backwards (popd).
alias f='pushd -0'         # go forwards (kind of like "unpopd").
 
#-------------------------------------------------------------
# Disk
#-------------------------------------------------------------
alias du='du -kh'          # Human-readable format.
alias dutotal='du -ch 2> /dev/null |tail -1'  # Displays only the total.
alias dutop10='du -hsx * | sort -rh | head -10'  # What is using the most space.
 
alias df='\df -kTh;\df -Thl --total | grep total'  # Adds total to the df command.
 
# Shows the individual partition usages without the temporary memory values.
alias dfx='\df -kThl --exclude-type=tmpfs --exclude-type=devtmpfs'
 
#-------------------------------------------------------------
# Directories.
#-------------------------------------------------------------
alias mkdir='mkdir -p'     # Make parent directories if needed.
alias back='cd $OLDPWD'    # Return to the last directory you were in.  Same as 'cd -'.
 
#-------------------------------------------------------------
# Downloading.
#-------------------------------------------------------------
alias wget='wget -c'       # -c flag to continue download in case of problems. 
alias wgetpage='wget --html-extension --recursive --convert-links --page-requisites --no-parent $1'
 
#-------------------------------------------------------------
# Files.
#-------------------------------------------------------------
alias fcount='ls -l | wc -l' # File count.
alias fcounta='ls -la | wc -l' # File count (incl hidden files).
alias fcountr='find . -type f | wc -l' # File count recursive.
alias lastmodified='find -type f -print0 | xargs -r0 stat -c %y\ %n | sort'
alias nocomment='grep -Ev "^(#|$)"'  # Show text file without comment (#) lines; or empty lines.
 
alias bigfiles='find . -type f 2>/dev/null | xargs du -a 2>/dev/null | awk "{ if ( \$1 > 5000) print \$0 }" | sort -hr'
alias verybigfiles='find . -type f 2>/dev/null | xargs du -a 2>/dev/null | awk "{ if ( \$1 > 500000) print \$0 }" | sort -hr'
 
alias brokenlinks='\find . -xtype l -printf "%p -> %l\n"'  # Find broken symlinks.
 
# count files by type - http://www.shell-fu.org/lister.php?id=173
alias ftype="find ${*-.} -type f | xargs file | awk -F, '{print $1}' | awk '{$1=NULL;print $0}' | sort | uniq -c | sort -nr"
 
#-------------------------------------------------------------
# File Permissions.
#-------------------------------------------------------------
alias fperm="find . -type f -exec chmod 0644 '{}' \;"
alias dperm="find . -type d -exec chmod 0755 '{}' \;"
 
#-------------------------------------------------------------
# Greps.
#-------------------------------------------------------------
alias grep='grep --color=auto'  # 
alias egrep='egrep --color=auto'  #
alias fgrep='fgrep --color=auto'  #
alias grepall='find . -name "*" | xargs grep --color=auto '
 
#-------------------------------------------------------------
# Logs.
#-------------------------------------------------------------
# alias syslog='sudo tail -10f /var/log/syslog'  # Follow syslog.
# alias messages='sudo tail -10f /var/log/messages'  # Follow messages.
 
# Last 10 items within every log file.
alias logs='tail -f /var/log/{dmesg,messages,*{,/*}{log,err}}'
 
#-------------------------------------------------------------
# ls.  (Assumes you use a recent GNU ls).
#-------------------------------------------------------------
alias ls='ls -h --color=auto'  # Add colors and human-readable sizes by default on 'ls'.
alias lsa='ls -A'          # Show hidden files.
alias lsd='ls -al -d * | egrep "^d"'
alias lsdf='ls -v --group-directories-first'  # Directories first, with alphanumeric sorting.
alias lsdt='ls -h --group-directories-first --time-style=+"%d.%m.%Y %H:%M" --color=auto -F'
alias lse='ls -AF | grep \*'  # Show executables only.
alias lsh='ls -Am'         # List files horizontally, comma-separated.
alias lsm='ls -Al |more'   # Pipe through 'more'.
alias lsne='ls -AF | grep -v \*'  # Show non executables only.
alias lsnx='ls -AF | egrep -v "\.|/"'  # Show only file without an extension.
alias lsr='ls -lR'         # List files recursively.
alias lssh='ls -Ax'        # Sort by name horizontally.
alias lsss='ls -Sr'        # Sort by size, biggest last.
alias lsssh='ls -shAxSr'   # Sort by size, biggest last, horizontally.
alias lsst='ls -Atr'       # Sort by date, most recent last
alias lssta='ls -Atur'     # Sort by/show access time,most recent last.
alias lsstc='ls -Atcr'     # Sort by/show change time,most recent last.
alias lssx='ls -AXB'       # Sort by extension.
alias lsx='ls -AF | egrep "\.|/"'  # Show only file with an extension.
 
alias ll='ls -lF'          # Long listing, classify.
alias lla='ls -lAF'        # All files, long listing.
alias lld='ls -lFA | grep :*/'  # List only directories, if any exist.
alias lldf='ls -lv --group-directories-first'  # Directories first, with alphanumeric sorting.
alias lldt='ls -lh --group-directories-first --time-style=+"%d.%m.%Y %H:%M" --color=auto -F'
alias lle='ls -lFA | grep \*'  # Show executables only.
alias llm='ll |more'       # Pipe through 'more'
alias llne='ls -lFA | grep -v \*'  # Show non executables only.
alias llnx='ls -lFA | egrep -v "\.|/"'  # Show only file without an extension.
alias llr='ll -lAR'        # Recursive ls.
alias llss='ls -lSr'       # Sort by size, biggest last.
alias llst='ls -lAtrh'     # Sort by date, most recent last, and human readable
alias llsta='ls -ltur'     # Sort by/show access time,most recent last.
alias llstc='ls -ltcr'     # Sort by/show change time,most recent last.
alias llsx='ls -lXB'       # Sort by extension.
alias llx='ls -lFA | egrep "\.|/"'  # Show only file with an extension.
 
alias tree='find . | sed "s/[^/]*\//|   /g;s/| *\([^| ]\)/+--- \1/"'  # Simple tree of current dir.
 
#-------------------------------------------------------------
# Memory.
#-------------------------------------------------------------
alias mem='echo -e Memory usage: $(free -h | grep "+" | cut -c26-30)/ $(free -h | grep "Mem:" | cut -c15-18)'
 
#-------------------------------------------------------------
# Misc.
#-------------------------------------------------------------
alias pause='read -n 1 -p "Press any key to continue…"'
alias restart='killall -SIGUSR1'
alias utf='iconv -f ISO-8859-1 -t UTF-8'
alias which='type -a'      # Includes aliases.
 
#-------------------------------------------------------------
# Networking.
#-------------------------------------------------------------
alias connections='sudo /usr/bin/lsof -i -P'
alias openports='netstat -lntp 2>/dev/null | grep -v " - *$"'  # Shows open ports.
alias macs='ifconfig | grep HWaddr'  # Shows MAC addresses for all nics.
alias nics='ifconfig em1 | egrep "[0-9]{1,3}(\.[0-9]{1,3}){3}"'  # Shows all nics.
alias ping='ping -c 5'  # Stop after sending count ECHO_REQUEST packets.
alias fastping='sudo ping -c 5 -s.2'  # Do not wait interval 1 second, go fast.
 
# Network diagnostic.
# Usage: mtr google.com
alias trace='mtr --report-wide --curses $1'
 
#-------------------------------------------------------------
# Path.
#-------------------------------------------------------------
# Pretty-print of some PATH variables:
alias path='echo -e ${PATH//:/\\n}'  # echo $PATH | tr ':' '\n'.
alias libpath='echo -e ${LD_LIBRARY_PATH//:/\\n}'
 
#-------------------------------------------------------------
# Processes.
#-------------------------------------------------------------
alias psc='ps h -eo pcpu,pmem,pid,comm,user,cputime | sort -nr | head'  # By CPU.
alias psm='ps h -eo pmem,pcpu,pid,comm,user,cputime | sort -nr | head'  # By Mem.
alias pstree='ps -e -o pid,args --forest'
alias psfull='ps -auxwww'  # ps with wide output so you can see full commands.
 
# usage: psg peter
# usage: psg ssh
alias psg='ps -Helf | grep -v $$ | grep -i -e WCHAN -e '  # ps grep.
 
# Show only my procs.
alias myps='ps -fHu $USER'     # if not $USER, try $LOGIN
 
#-------------------------------------------------------------
# Programming – C/C++/Java/PHP.
#-------------------------------------------------------------
# Count lines of php code under the current directory.
alias countphp='find . -name "*.php" -print0 | xargs -0 wc'
 
# Count lines of java code under the current directory.
alias countjava='find . -name "*.java" -print0 | xargs -0 wc'
 
# Count lines of C or C++ or Obj-C code under the current directory.
alias countc='find . \( -name "*.c" -or -name "*.cpp" -or -name "*.h" -or -name "*.m" \) -print0 | xargs -0 wc'
 
# Count lines of C or C++ or Obj-C or Java or PHP code under the current directory.
alias countcode='find . \( -name "*.c" -or -name "*.cpp" -or -name "*.h" -or -name "*.m" -or -name "*.java" -or -name "*.php" \) -print0 | xargs -0 wc'
 
#-------------------------------------------------------------
# Spelling typos.  Highly personal and keyboard-dependent.
#-------------------------------------------------------------
alias xs='cd'
alias vf='cd'
alias moer='more'
alias moew='more'
alias kk='ll'
 
#-------------------------------------------------------------
# Text.
#-------------------------------------------------------------
 
# Truncate lines longer than 80 characters (for use in pipes).
alias cut80='/usr/bin/cut -c 1-80'
 
alias tn='tr -d "\n"'  # trim newlines.
 
#-------------------------------------------------------------
# Time.
#-------------------------------------------------------------
alias now='date +"%T"'
alias nowtime=now
alias nowdate='date +"%Y-%m-%d"'
 
#-------------------------------------------------------------
# Web.
#-------------------------------------------------------------
# Pass it via sudo so whoever is admin can reload it without calling you.
alias nginxreload='sudo /usr/sbin/nginx -s reload'
alias nginxtest='sudo /usr/sbin/nginx -t'

It is important to note that the aliases will only be read when the shell is created. Therefore, you won’t see any changes to the aliases immediately. You need to either create a new shell after saving your modified /etc/profile.d/bash_aliases file or to (re)load the file like this:

sudo /etc/profile.d/bash_aliases.sh

Add Global Functions

Bash functions store a series of commands for later execution. If a sequence of commands is run frequently, it would make sense to wrap them up in a function. Functions are a lot like aliases but you can also pass arguments to them.

Functions act as a compromise between aliases and scripts. They are usually much simpler than full-blown scripts.

Global Functions would normally be added to the /etc/profile file, but it’s cleaner to have a separate file for the functions.

NOTE: A user can overwrite the global functions if needed by define their own functions within their .bashrc, .bash_aliases, or .profile files within their own home directories.

Issue the following command:

sudo vi /etc/profile.d/bash_functions.sh

and add the following to the file:

/etc/profile.d/bash_functions.sh
#-------------------------------------------------------------
# Archiving functions.
#-------------------------------------------------------------
 
# Creates an archive.
archive() {
  if [ "$#" -ne 0 ] ; then
    FILE="$1"
    case "$FILE" in
      *.tar.bz2|*.tbz2) shift && tar cvjf "$FILE" $* ;;
      *.tar.gz|*.tgz)   shift && tar cvzf "$FILE" $* ;;
      *.tar)            shift && tar cvf "$FILE" $* ;;
      *.rar)            shift && rar "$FILE" $* ;;
      *.zip)            shift && zip "$FILE" $* ;;
      *.7z)             shift && 7zr a "$FILE" $* ;;
      *)                echo "'$1' cannot be archived via archive()" ;;
    esac
  else
    echo "usage: archive [file] [contents]"
  fi
}
 
 
# Extract an archive of any type.
extract() {
  local opt
  local OPTIND=1
  while getopts "hv?" opt; do
    case "$opt" in
      h)
        cat <<End-Of-Usage
Usage: ${FUNCNAME[0]} [option] <archives>
    options:
        -h  show this message and exit
        -v  verbosely list files processed
End-Of-Usage
        return
        ;;
      v)
        local -r verbose='v'
        ;;
      ?)
        extract -h >&2
        return 1
        ;;
    ac
  done
  shift $((OPTIND-1))
 
  [ $# -eq 0 ] && extract -h && return 1
  while [ $# -gt 0 ]; do
    if [ -f "$1" ]; then
      case "$1" in
        *.tar.bz2|*.tbz|*.tbz2) tar "xvjf" "$1" ;;
        *.tar.gz|*.tgz) tar "xvzf" "$1" ;;
        *.tar.xz) xz --decompress "$1"; set -- "$@" "${1:0:-3}" ;;
        *.tar.Z) uncompress "$1"; set -- "$@" "${1:0:-2}" ;;
        *.bz2) bunzip2 "$1" ;;
        *.deb) dpkg-deb -xv "$1" "${1:0:-4}" ;;
#        *.deb) sudo dpkg -i $1 ;;
        *.exe) cabextract "$1" ;;
        *.pax.gz) gunzip "$1"; set -- "$@" "${1:0:-3}" ;;
        *.gz) gunzip "$1" ;;
        *.lzma) unlzma "$1" ;;
        *.pax) pax -r -f "$1" ;;
        *.pkg) pkgutil --expand "$1" "${1:0:-4}" ;;
        *.rar) unrar x "$1" ;;
        *.rpm) rpm2cpio "$1" | cpio -idmv ;;
#        *.rpm) sudo alien -dik $1;;
        *.tar) tar "xvf" "$1" ;;
        *.txz) mv "$1" "${1:0:-4}.tar.xz"; set -- "$@" "${1:0:-4}.tar.xz" ;;
        *.xz) xz --decompress "$1" ;;
        *.zip|*.war|*.jar) unzip "$1" ;;
        *.Z) uncompress "$1" ;;
        *.7z) 7za x "$1" ;;
        *) echo "'$1' cannot be extracted via extract" >&2;;
      esac
    else
      echo "extract: '$1' is not a valid file" >&2
    fi
    shift
  done
}
 
 
# ls archives (inspired by `extract`)
lsz() {
  if [ $# -ne 1 ]
  then
    echo "lsz filename.[tar,tgz,gz,rar,zip,etc]"
    return 1
  fi
  if [ -f $1 ] ; then
    case $1 in
      *.tar.bz2|*.tar.gz|*.tar|*.tbz2|*.tgz) tar tvf $1;;
      *.rar)  unrar l $1;;
      *.zip)  unzip -l $1;;
      *)      echo "'$1' unrecognized." ;;
    esac
  else
    echo "'$1' is not a valid file"
  fi
}
 
 
# Creates an archive (*.tar.gz) from given directory.
maketar() { tar cvzf "${1%%/}.tar.gz"  "${1%%/}/"; }
 
# Create a ZIP archive of a file or folder.
makezip() { zip -r "${1%%/}.zip" "$1" ; }
 
 
#-------------------------------------------------------------
# Calculator functions.
#-------------------------------------------------------------
 
# Calculate an expression e.g. calc 1+1.
calc() {
  echo "$@"|bc -l;
}
 
 
#-------------------------------------------------------------
# cd.
#-------------------------------------------------------------
 
# cd = pushd, b = go backwards (popd), f = go forwards (kind of like "unpopd").
#alias d='dirs'
#alias b='pushd +1'
#alias f='pushd -0'
cd() {
  if [ "$*" = "" ]; then
    pushd $HOME >/dev/null
  else
    pushd "$*" >/dev/null
  fi
}
 
 
# cd to the directory a symbolically linked file is in.
cdlink {
  if [ "x$1" = "x" ] ; then
    echo "Missing Arg"
  elif [ -L "$1" ] ; then
    link=`/bin/ls -l $1 | tr -s ' ' | cut -d' ' -f10`
    if [ "x$link" = "x" ] ; then
      echo "Failed to get link"
      return
    fi
    dirName_=`dirname $link`
    cd "$dirName_"
  else
    echo "$1 is not a symbolic link"
  fi
  return
}
 
 
# cd to the dir that a file is found in.
cdff {
  filename=`find . -name $1 | grep -iv "Permission Denied" | head -1`
  if [ "xx${filename}xx" != "xxxx" ] ; then
    dirname=${filename%/*}
    if [ -d $dirname ] ; then
      cd $dirname
    fi
  fi
}
 
 
#-------------------------------------------------------------
# Directory functions.
#-------------------------------------------------------------
 
# Jumps to a directory at any level below using globstar.
jd() {
  if [ -z $1 ]; then
    echo "Usage: jd [directory]";
    return 1
  else
    cd **/$@
  fi
}
 
 
# Go up a specified number of directories.
# If you pass no arguments, it just goes up one directory.
# If you pass a numeric argument it will go up that number of directories.
# If you pass a string argument, it will look for a parent directory with that name and go up to it.
up() {
  dir=""
  if [ -z "$1" ]; then
    dir=..
  elif [[ $1 =~ ^[0-9]+$ ]]; then
    x=0
    while [ $x -lt ${1:-1} ]; do
      dir=${dir}../
      x=$(($x+1))
    done
  else
    dir=${PWD%/$1/*}/$1
  fi
  cd "$dir";
}
 
 
#-------------------------------------------------------------
# Disk functions.
#-------------------------------------------------------------
 
# Pretty-print of 'df' output.
# Inspired by 'dfc' utility.
mydf() {               
  for fs ; do
 
    if [ ! -d $fs ]
    then
      echo -e $fs" :No such file or directory" ; continue
    fi
 
    local info=( $(command df -P $fs | awk 'END{ print $2,$3,$5 }') )
    local free=( $(command df -Pkh $fs | awk 'END{ print $4 }') )
    local nbstars=$(( 20 * ${info[1]} / ${info[0]} ))
    local out="["
    for ((j=0;j<20;j++)); do
      if [ ${j} -lt ${nbstars} ]; then
        out=$out"*"
      else
        out=$out"-"
      fi
    done
    out=${info[2]}" "$out"] ("$free" free on "$fs")"
    echo -e $out
  done
}
 
 
#-------------------------------------------------------------
# Downloading functions.
#-------------------------------------------------------------
 
# More persistent wget for fetching files to a specific filename.
wgettofile() {
  [ $# -ne 2 ] && echo "usage: wgettofile <url> <filename>" && return 1
  urltofetch=$1
  fname="$2"
  wget -O "$fname" $urltofetch
}
 
 
#-------------------------------------------------------------
# Email functions.
#-------------------------------------------------------------
 
# Email me a short note.
emailme() {
  if [ $# -eq 0 ]
  then
    echo Usage: emailme text
    return 1
  fi
  echo "$*" | mailx -s "$*" administrator
  echo "Sent email"
}
 
 
#-------------------------------------------------------------
# File functions.
#-------------------------------------------------------------
 
# Backup file(s)
filebackup() {
  if [ $# -lt 1 ]
  then
    echo Please supply a file to backup
    return 1
  fi
  date=`date +%Y%m%d-%H%M%S`
  for i in "$@"
  do
    echo Backed up $i to $i.$date
    cp "$i" "$i".$date
  done
}
 
 
# Output a text file with line numbers
#
# Overriding the newline-to-tab conversion (with the -d flag) and
# replacing newlines with TAB-newline, maintaining the newline 
# but indenting it. sed = will number the lines in the output, 
# and the -s switch on paste will restore our whitespace keeping 
# the line number justified to the left.
filecatno() {
  if [ $# == 0 ]; then
    echo "No filename provided."
  else
    sed = "$1" | paste -s -d '\t\n' - -
  fi
}
 
 
# Show all strings (ASCII & Unicode) in a file.
filecatstr() { cat "$1" | tr -d "\0" | strings ; }
 
 
# Changes the extension of all of the specified files in a directory.
# It takes two arguments, first the original extension, 
# then the extension to replace it with. 
# For example
#   filechgext html php
filechgext() {
  for file in *.$1 ; do mv "$file" "${file%.$1}.$2" ; done
}
 
 
# Find a file with pattern $1 in name and Execute $2 on it:
fileexec() { 
  find . -type f -iname '*'"${1:-}"'*' \
    -exec ${2:-file} {} \;  ; 
}
 
 
 
# Fast find, using globstar.
filefind() {
  ls -ltr **/$@
}
 
 
# Swap 2 filenames around, if they exist.
fileswap() {
  local TMPFILE=tmp.$$
 
  [ $# -ne 2 ] && echo "Usage: fileswap file1 file2" && return 1
#  [ $# -ne 2 ] && echo "fileswap: 2 arguments needed" && return 1
  [ ! -e $1 ] && echo "fileswap: $1 does not exist" && return 1
  [ ! -e $2 ] && echo "fileswap: $2 does not exist" && return 1
 
  mv "$1" $TMPFILE
  mv "$2" "$1"
  mv $TMPFILE "$2"
}
 
 
# Moves file to ~/.Trash (use instead of rm).
filetrash() {
  if [ $# -eq 0 ]
  then
    echo Usage: filetrash FILE...
    return 1
  fi
  local DATE=$(date +%Y%m%d)
  [ -d "${HOME}/.Trash/${DATE}" ] || mkdir -p ${HOME}/.Trash/${DATE}
  for FILE in "$@"
  do
    mv "${FILE}" "${HOME}/.Trash/${DATE}"
    echo "${FILE} trashed!"
  done
}
 
 
# Overwrite a file with zeroes - http://www.shell-fu.org/lister.php?id=94
filezero() {
  case "$1" in
    "")     echo "Usage: filezero "
            return -1;
  esac
  filesize=`wc -c  "$1" | awk '{print $1}'`
  dd if=/dev/zero of=$1 count=$filesize bs=1
}
 
 
#-------------------------------------------------------------
# Firewall functions.
#-------------------------------------------------------------
 
# Ban IP 
ban() {
  if [ "`id -u`" == "0" ] ; then
    iptables -A INPUT -s $1 -j DROP
  else
    sudo iptables -A INPUT -s $1 -j DROP
  fi
}
 
 
#-------------------------------------------------------------
# Grep Find Search functions.
#-------------------------------------------------------------
 
# Find a file with a pattern in name:
# Examples:
#   ff ash
ff() { find . -type f -iname '*'"$*"'*' -ls ; }
 
# Find a file whose name starts with a given string.
ffs() { /usr/bin/find . -name "$@"'*' ; }
 
# Find a file whose name ends with a given string.
ffe() { /usr/bin/find . -name '*'"$@" ; }
 
# Find files larger than a certain size (in bytes).
ffbigger() { find . -type f 2>/dev/null | xargs \du -a -b 2>/dev/null | awk "{ if ( \$1 > $@) print \$0 }" | sort -hr; }
 
# Find a pattern in a set of files and highlight them:
#+ (needs a recent version of egrep).
findstr() {
  OPTIND=1
  local mycase=""
  local usage="findstr: find string in files.
Usage: grepstr [-i] \"pattern\" [\"filename pattern\"] "
  while getopts :it opt
  do
    case "$opt" in
      i) mycase="-i " ;;
      *) echo "$usage"; return ;;
    esac
  done
  shift $(( $OPTIND - 1 ))
  if [ "$#" -lt 1 ]; then
    echo "$usage"
    return;
  fi
  find . -type f -name "${2:-*}" -print0 | \
    xargs -0 egrep --color=always -sn ${case} "$1" 2>&- | more
}
 
 
# Search for a word in the Unix word list.
word() { /bin/grep ^"$@"$ /usr/share/dict/words ; }
 
# Search for a word in the Unix word list that ends with the chars.
wordstarts() { /bin/grep ^"$@" /usr/share/dict/words ; }
 
# Search for a word in the Unix word list that ends with the chars.
wordends() { /bin/grep "$@"$ /usr/share/dict/words ; }
 
 
#-------------------------------------------------------------
# Info functions.
#-------------------------------------------------------------
 
# Get current host related info.
ii() {
  echo -e "\nYou are logged on ${BRed}$HOST"
  echo -e "\n${BRed}Additionnal information:$NC " ; uname -a
  echo -e "\n${BRed}Users logged on:$NC " ; w -hs |
    cut -d " " -f1 | sort | uniq
  echo -e "\n${BRed}Current date :$NC " ; date
  echo -e "\n${BRed}Machine stats :$NC " ; uptime
  echo -e "\n${BRed}Memory stats :$NC " ; free
  echo -e "\n${BRed}Diskspace :$NC " ; mydf / $HOME
  echo -e "\n${BRed}Local IP Address :$NC" ; my_ip
  echo -e "\n${BRed}Open connections :$NC "; netstat -pan --inet;
  echo
}
 
 
#-------------------------------------------------------------
# Misc functions.
#-------------------------------------------------------------
 
# Waits for the user to press a y or n.
#
# Example:
#        if ask "Kill process $pid <$pname> with signal $sig?"
#            then kill $sig $pid
#        fi
ask()          
{
  echo -n "$@" '[y/n] ' ; read ans
  case "$ans" in
    y*|Y*) return 0 ;;
    *) return 1 ;;
  esac
}
 
 
# Repeat n times command.
#
# Example:
#   repeat 10 ls
repeat()
{
  local i max
  max=$1; shift;
  for ((i=1; i <= max ; i++)); do  # --> C-like syntax
    eval "$@";
  done
}
 
 
# Do something very quietly.
runquiet() {
  ( $@ ) >/dev/null 2>/dev/null
}
 
 
#-------------------------------------------------------------
# Network functions.
#-------------------------------------------------------------
 
# myIP address
ipall() {
  ifconfig lo | grep 'inet ' | sed -e 's/:/ /' | awk '{print "lo: " $2 " " $3 " " $4 " " $5 " " $6}'
  ifconfig em1 | grep 'inet ' | sed -e 's/:/ /' | awk '{print "em1 (IPv4): " $2 " " $3 " " $4 " " $5 " " $6}'
  ifconfig em1 | grep 'inet6 ' | sed -e 's/ / /' | awk '{print "em1 (IPv6): " $2 " " $3 " " $4 " " $5 " " $6}'
  ifconfig em2 | grep 'inet ' | sed -e 's/:/ /' | awk '{print "em2 (IPv4): " $2 " " $3 " " $4 " " $5 " " $6}'
  ifconfig em2 | grep 'inet6 ' | sed -e 's/ / /' | awk '{print "em2 (IPv6): " $2 " " $3 " " $4 " " $5 " " $6}'
}
 
 
# Get IP adress on ethernet.
myip() {
  MY_IP=$(/sbin/ifconfig em1 | awk '/inet/ { print $2 } ' |
    sed -e s/addr://)
  echo ${MY_IP:-"Not connected"}
}
 
 
getip() {
  for each in $@; do
    echo $each
    echo "nslookup:"
    nslookup $each | grep Address: | grep -v '#' | egrep -o '([0-9]+\.){3}[0-9]+'
    echo "ping:"
    ping -c1 -t1 $each | egrep -o '([0-9]+\.){3}[0-9]+' | head -n1
  done
}
 
 
#-------------------------------------------------------------
# Process functions.
#-------------------------------------------------------------
 
psnice() {
  if ! [ -z "$1" ] 
  then
    # Take a parameter pid.
    ionice -c3 -p$1 ; renice -n 19 -p $1
  else
    # If no parameter is nice the current pid (bash).
    ionice -c3 -p$$ ; renice -n 19 -p $$
  fi
}
 
 
#-------------------------------------------------------------
# String functions.
#-------------------------------------------------------------
 
# substring word start [length]
substring() {
  if [ $# -lt 2 ]; then
    echo "Usage: substring word start [length]"
    return 1
  fi
  if [ -z $3 ]
  then
    echo ${1:$2}
  else
    echo ${1:$2:$3}
  fi
}
 
 
# Get length of string.
strlen() {
  if [ $# -ne 1 ]; then
    echo "Usage: length word"
    return 1
  fi
  echo ${#1}
}
 
 
# Convert string to upper-case.
strupper() {
  if [ $# -lt 1 ]; then
    echo "Usage: upper word"
    return 1
  fi
  echo ${@^^}
}
 
 
# Convert string to lower-case.
strlower() {
  if [ $# -lt 1 ]; then
    echo "Usage: lower word"
    return 1
  fi
  echo ${@,,}
}
 
 
# Replace part of string with another.
strreplace() {
  if [ $# -ne 3 ]; then
    echo "Usage: replace string substring replacement"
    return 1
  fi
  echo ${1/$2/$3}
}
 
 
# Replace all parts of a string with another.
strreplaceall() {
  if [ $# -ne 3 ]; then
    echo "Usage: replace string substring replacement"
    return 1
  fi
  echo ${1//$2/$3}
}
 
 
# Find index of specified string.
strindex() {
  if [ $# -ne 2 ]; then
    echo "Usage: index string substring"
    return 1
  fi
  expr index $1 $2
}
 
 
# Surround lines with quotes (useful in pipes).
strquote() { 
  echo "$@" | /bin/sed 's/^/"/;s/$/"/' ; 
}
 
 
# Surround string with whatever is given as 2nd param.
#
# Example:
#   strsurround abc 123
#   strsurround abc \"
#   strsurround abc \\\\
strsurround() {
  if [ $# -ne 2 ]
  then
    echo Usage: surround string surround-with e.g. surround hello \\\\
    return 1
  fi
  echo $1 | sed "s/^/$2/;s/$/$2/" ;
}
 
 
#-------------------------------------------------------------
# USB functions.
#-------------------------------------------------------------
# Need to figure out which drive your usb is assigned? Functions work the same way as an alias. Simply copy the line into your .profile/.bashrc file. Then type: myusb
myusb() { 
  usb_array=();while read -r -d $'\n'; do usb_array+=("$REPLY"); done < <(find /dev/disk/by-path/ -type l -iname \*usb\*scsi\* -not -iname \*usb\*scsi\*part* -print0 | xargs -0 -iD readlink -f D | cut -c 8) && for usb in "${usb_array[@]}"; do echo "USB drive assigned to sd$usb"; done; 
}

It is important to note that the functions will only be read when the shell is created. Therefore, you won’t see any changes to the functions immediately. You need to either create a new shell after saving your modified /etc/profile.d/bash_functions file or to (re)load the file like this:

sudo . /etc/profile.d/bash_functions.sh

Allow colour prompts for the root and sudo users (highly recommended)

Issue the following command:

sudo vi /root/.bashrc

and remove the hash from the begin of the force_color_prompt line:

/root/.bashrc
force_color_prompt=yes

This functionality is not required, but does makes it a lot easier to see what’s going on, so recommended.


Issue the following command:

sudo vi /home/administrator/.bashrc

and remove the hash from the begin of the force_color_prompt line:

/home/administrator/.bashrc
force_color_prompt=yes

This functionality is not required, but does makes it a lot easier to see what’s going on, so recommended.


Restart the System

To enable the changes to be recognized, restart the system. Issue the following command:

sudo reboot

…and log back in using a SSH client, such as Putty.


Login using a SSH Client

ssh adminstrator@192.168.1.2

The terminal will show something like:

The authenticity of host '69.55.55.20 (69.55.55.20)' can't be established.
ECDSA key fingerprint is 79:95:46:1a:ab:37:11:8e:86:54:36:38:bb:3c:fa:c0.
Are you sure you want to continue connecting (yes/no)?

Go ahead and type yes, and then enter the password of the administrator, adminpass.


Continue

Continue to Base Security