Skip to content

Bash and shell scripting tips and tricks

Michael Hulse edited this page Jun 14, 2019 · 2 revisions

Find/replace text in file

Use sed to find/replace text in a file:

sed -i 's/EnableSendfile on/EnableSendfile off/i' /etc/httpd/conf/httpd.conf

Root

If you need to be root, do this:

# Switch to `root` user and start in `/root`:
$ sudo -i
# Same as above, but no directory switch:
$ sudo -s
# Invoke login shell after switching user (resets most environment variables, providing a clean base):
$ sudo su -
# … or:
$ sudo su
# Same as above, more explicit:
$ sudo su - root
# ... or, to switch to another user account:
$ sudo su <user>

Semi colons ;

Semi colons are use when EOL is missing; if EOL exists, no semi colon is required.

Assignment

When assigning, no spaces around the =.

foo='baz'
echo $foo

Conditionals

When comparing, put spaces before and after the =.

foo='baz';
if [ $foo = 'baz' ]
    then
        echo $foo
fi

Scope

var="$(fdisk -l)"

The above variable is only available to the current shell. If it's an environment variable, you can export it to descendant shells:

export VAR="$(fdisk -l)"

See: Thread: How can I redirect stdout to a variable

Previous directory

$ cd -
$ cd ~- # Eats the return value of the above.

This will let you change directory to your previous location in the file system. It’s and easy way switch back and forth between two directories.

Most of the time you don't want to maintain two separate config files for login and non-login shells — when you set a PATH, you want it to apply to both. You can fix this by sourcing .bashrc from your .bash_profile file, then putting PATH and common settings in .bashrc.

To do this, add the following lines to .bash_profile:

if [ -f ~/.bashrc ]; then source ~/.bashrc fi


> Now when you login to your machine from a console .bashrc will be called.

Alternatively, you could make `.bash_profile` your main config file by adding this:

```bash
# Nothing to see here — Everything's in .bash_profile:
[ -n "$PS1" ] && source ~/.bash_profile

… to your .bashrc file (thank you Bashstrap!)

Better history

Unfortunately, the default history length in OS X is 500 commands. That seems like a lot, but when you're running 50+ commands a day it can push older commands off the list pretty quickly. This is easily solved by setting the HISTFILESIZE in your .bash_profile file.

HISTFILESIZE=

Source: How to increase bash shell history length in OS X

Here's my current .bash_profile:

# http://unix.stackexchange.com/questions/1288/preserve-bash-history-in-multiple-terminal-windows
# http://superuser.com/questions/137438/how-to-unlimited-bash-shell-history
# https://www.kernel.org/doc/man-pages/online/pages/man3/strftime.3.html
export HISTCONTROL=ignoredups:erasedups  # No duplicate entries.
export HISTSIZE=100000                   # Big BIG history.
export HISTFILESIZE=100000               # Big BIG history.
export HISTTIMEFORMAT="%a %h %d - %r "   # Timestamp.
shopt -s histappend                      # Append to history, don't overwrite it.
# Save and reload the history after each command finishes:
export PROMPT_COMMAND="history -a; history -c; history -r; $PROMPT_COMMAND"

From the $ man bash:

If HIST‐FILESIZE is not set, no truncation is performed.

... and:

If the HISTTIMEFORMAT variable is set, time stamps are written to the history file, marked with the history comment character, so they may be preserved across shell sessions.

Some interesting info here:

Preserve bash history in multiple terminal windows

Colors/theme

Better color/readability, put this in your .bash_profile:

# http://noahfrederick.com/blog/2011/lion-terminal-theme-peppermint/
# http://osxdaily.com/2013/02/05/improve-terminal-appearance-mac-os-x/
# http://stackoverflow.com/questions/1550288/mac-os-x-terminal-colors
export PS1="\[\e[0;31m\]\u\[\e[0m\]@\[\e[0;32m\]\h\[\e[0m\]:\[\e[0;34m\]\w\[\e[0m\]\$ "
export CLICOLOR=1
export LSCOLORS=ExFxBxDxCxegedabagacad
alias ls='ls -GFh'

… Or, use the color theme from: Bashstrap.

Reload using $ source .bash_profile.

It also helps to turn on all "Text" options under Preferences > Settings > [Theme] > Text.

Within same section, click on the Window button and adjust the opacity/blur of the "Background" (click on "Color & Effects").

Here's a theme I like:

SSH -t

SSH -t Force pseudo-tty allocation. This can be used to execute arbitrary screen-based programs on a remote machine, which can be very useful, e.g. when implementing menu services. Multiple -t options force tty allocation, even if ssh has no local tty.

# Create and edit text file on remote machine:
ssh -t -i ~/.ssh/foo.pem [email protected] vi /tmp/myfile.txt
# Run `top`:
ssh -t -i ~/.ssh/foo.pem [email protected] top

Here's a bash alias used to restart Apache on a remote machine:

# Restart Apache (Unbuntu):
restart-foo='ssh -i ~/.ssh/foo.pem [email protected] sudo service apache2 restart'

Find

Traverse entire machine to find a file name:

$ sudo find / -name "Xcode"

sudo will suppress barking when trying to read directories where your ordinary login wouldn't have adequate privileges.

/ starts the search at the machine root and starts working its way down.

Locate

An alternative to find (above) is locate.

$ locate
usage: locate [-0Scims] [-l limit] [-d database] pattern ...
default database: `/var/db/locate.database' or $LOCATE_PATH

$ locate websitesoff403.html
WARNING: The locate database (/var/db/locate.database) does not exist.
To create the database, run the following command:

  sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.locate.plist

Please be aware that the database can take some time to generate; once
the database has been created, this message will no longer appear.

$ sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.locate.plist

Now, after the database has been built, you can do some fast searching of your local machine.

Grep

Find keyword in file:

$ grep -i error /etc/php.ini

Environment variables

This will print environmental variables "right now":

$ env

It shows you the useful ones, that you need need to know right now.

Get PIDs

The ps (i.e., process status) command is used to provide information about the currently running processes, including their process identification numbers (PIDs):

$ ps

That will show you what unix shell you're using.

Permissions

Hidden files:

$ sudo chmod -R g+w *.*

Everything else:

$ sudo chmod -R g+w *

Change user/group for everything in www/:

$ sudo chown -R apache:apache www/*

Change group for .htaccess file:

$ sudo chown apache:apache html/.htaccess

You could also:

$ sudo bash

... then just drop "sudo" from those other commands.

“Normalize” permissions on files/directories

$ find ./directory -type f -exec chmod 0664 {} \;
$ find ./directory -type d -exec chmod 0755 {} \;

Links

Clone this wiki locally