The article in the Ghost in the Shell series was the first post on my blog, so while I was busy by writing various server related articles and recently the FreeBSD Desktop series its about time for the Part 2 of the Ghost in the Shell series.

You may want to check other articles in the Ghost in the Shell series on the Ghost in the Shell – Global Page where you will find links to all episodes of the series along with table of contents for each episode’s contents.

Lets start with something simple – yet powerful and time saving.

Alias with Arguments

One may of course write any function to do similar job, but keeping track and ‘maintaining’ all those functions becomes complicated and one has to organize itself. This partially applies to aliases, but they are smaller and easier to maintain then whole functions. In any modern shell an alias(1) can also have arguments, while You will not be able to parse them as appropriate as with functions, they do the job for their basic use.

Here is an example of such alias(1) with arguments.

% ls gfx/ info/ misc/ scripts/ tmp/ % alias lsg='ls | grep' % lsg gfx gfx/

Color grep(1) Patterns

As we already ‘touched’ the grep(1) command topic, lets make it more usable by highlighting the found results in color. The ${GREP_COLOR} variable is used for that purpose and it expects a number for a color, here is the table with number-color format.

Color Number Black 30 Red 31 Green 32 Yellow 33 Blue 34 Magenta 35 Cyan 36 White 37

You may as well use ‘bold’ output by adding ‘ 1; ‘ before the number, for example.

% echo ${GREP_COLOR} 1;31

You will also have to make an alias(1) to grep(1) with --color argument, like that:

% alias grep='grep --color'

Here is how it looks in practice.

% export GREP_COLOR=31 % alias grep='grep --color' % dmesg | grep SMP FreeBSD/ SMP : Multiprocessor System Detected: 2 CPUs FreeBSD/ SMP : 1 package(s) x 2 core(s) SMP : AP CPU #1 Launched!

Here is how it looks on the xterm(1) terminal.

Process Management

This one is very useful on any UNIX system, does not matter if its server or desktop.

These are commands and operands that will help us manage processes started by hand:

&

fg

bg

jobs

kill

disown

nohup

[CTRL]+[Z]

[CTRL]+[C]

As you probably already know to start command ‘in the background’ – which means do what I tell you but do not block the terminal – you have to add ‘ & ‘ (ampersand) at the end of such command. That command does not magically go away and as long as its running its visible by the jobs(1) command. You may use ‘ -l ‘ switch to also show the PID of background processes.

% galculator & [1] 8449 % jobs [1] + running galculator % jobs -l [1] + 8449 running galculator

Now, what of you forget to add ‘ & ‘ (ampersand) at the end of command but you wanted to put it into the background? Hit [CTRL]+[Z] shortcut (Control key with ‘small’ Z letter) and the process will be put into the suspended state. Now you have several options, you can out that process into the background with bg(1) command – by default it uses last suspended job – %1 , you can also bring it back into the foreground blocking the terminal with fg(1) command. You can also list its state with jobs(1) and of course kill(1) it either with PID showed by jobs -l command or by specifying the process number – %1 in that case.

Here is an example.

% galculator ^Z zsh: suspended galculator % jobs [1] + suspended galculator % bg [1] + continued galculator % jobs -l [1] + 72892 running galculator % kill %1 [1] + terminated galculator %

While fg(1) and bg(1) allow you to put command in the background or foreground respectively when the process is in suspended state, one may ask how to ‘switch’ a process to suspended state while its already running in the background. Its done with kill -17 signal called SIGSTOP . You can also bring back such suspended process to running state with kill -19 signal called SIGCONT … or just again use fg(1) or bg(1) command. Other difference between fg(1) / bg(1) commands and more ‘direct’ kill -17 / kill -19 commands are that kill(1) does not inform the user what has changed to the process. You may as well use kill -SIGCONT syntax or kill -s SIGCONT if that is more readable for you.

% galculator ^Z zsh: suspended galculator % bg [1] + continued galculator % xcalc ^Z zsh: suspended xcalc % jobs -l [1] - 19537 running galculator [2] + 20563 suspended xcalc % kill -17 %1 [1] + suspended (signal) galculator % jobs -l [1] + 19537 suspended (signal) galculator [2] - 20563 suspended xcalc % kill -SIGCONT %1 % bg %2 [2] - continued xcalc % jobs -l [1] + 19537 running galculator [2] - 20563 running xcalc

Also check man kill and man signal for more information.

What about disown(1) then? Its a ‘magic’ helper when you start some long running jobs directly at the terminal without Screen or Tmux and you need to disconnect that terminal, for example because you are taking your laptop with you. When you do this – depending on the settings of the current shell – the processes in the background may be killed or ‘moved’ to PID 1 (the init(1) of course) as the PPID (Parent PID). To achieve that we will used that disown(1) command. Once you ‘disown’ a process it will no longer be show by the jobs(1) command, but it will run ‘pinned’ to the init(1) process after you disconnect the terminal session.

% galculator ^Z zsh: suspended galculator % bg [1] + continued galculator % jobs -l [1] + 98556 running galculator % disown %1 % jobs -l % pgrep galculator 98556 % pstree -p 98556 ─┬◆ 00001 root /sbin/init -- └─┬─ 48708 vermaden xterm └─┬◆ 52463 vermaden -zsh (zsh) └──◆ 98556 vermaden galculator

Now its still pinned to the shell in the xterm(1) terminal. After we close the xterm(1) window (or kill that zsh(1) shell) it will switch to init(1) as PPID (Parent PID).

% pstree -p 98556 ─┬◆ 00001 root /sbin/init -- └──◆ 98556 vermaden galculator % pgrep -P 1 galculator 98556

We are left with nohup(1) then, when and why to use it as we already has great disown(1) magic? Well, disown(1) is not always available, so when You need to put some command into the long background run and disconnect after it its the best possible option. By default the nohup(1) command will log the output of started command into the nohup.out file. Remember that nohup(1) will still run the process in the foreground, to put it into the background use ‘ & ‘ (ampersand) or [CTRL]+[Z] with bg(1) combo.

% nohup galculator appending output to nohup.out ^Z zsh: suspended nohup galculator % bg [1] + continued nohup galculator % jobs -l [1] + 22322 running nohup galculator % pstree -p 22322 ─┬◆ 00001 root /sbin/init -- └─┬─ 89568 vermaden xterm └─┬◆ 91486 vermaden -zsh (zsh) └──◆ 22322 vermaden galculator

… and after disconnect out process switched to init(1) as PPID.

% pstree -p 22322 ─┬◆ 00001 root /sbin/init -- └──◆ 22322 vermaden galculator

You may of course end a running process in the foreground with [CTRL]+[C] shortcut, but that is probably already known to you. I just mention it for the ‘completeness’ of the guide.

% galculator ^C %

Which Which

While the which(1) command shows the full path of the executable found in the first directory of the ${PATH} variable, it also shows what alias is used for that command it there is one. One may ask how then to find information about absolute executable path if it shows and alias(1) instead. Well, you have to use unalias(1) on that command, so which(1) would be showing full path again.

% which caja caja: aliased to caja --browser --no-desktop % unalias caja % which caja /usr/local/bin/caja

Also be sure to check Smylers comment below about the difference between shell builtin which and /bin/which command.

Record Session

If you have used PuTTY or MobaXterm in your work, then you appreciate the possibility of saving the terminal output to a file, foe example for the documentation purposes. This is also available ‘natively’ in the shell by using the script(1) command. Remember that script(1) will record also ‘special’ characters like colors, so to properly ‘replay’ the session you may want to either use script(1) or cat(1) commands for that or use less with -R argument.

Here is example recorded script(1) session.

% script script.out Script started, output file is script.out % ls gfx info misc scripts tmp unix.png % uname -spr FreeBSD 11.2-RELEASE amd64 % exit Script done, output file is script.out % cat script.out Script started on Sun Jul 8 08:24:06 2018 You have mail. % ls | grep gfx gfx % uname -spr FreeBSD 11.2-RELEASE amd64 % exit exit Script done on Sun Jul 8 08:24:20 2018 % less -R script.out Script started on Sun Jul 8 08:24:06 2018 You have mail. % ls | grep gfx gfx % uname -spr FreeBSD 11.2-RELEASE amd64 % exit exit Script done on Sun Jul 8 08:24:20 2018 % less script.out Script started on Sun Jul 8 08:24:06 2018 You have mail. % ls | grep gfx ESC[1;31mgfxESC[00mESC[K % uname -spr FreeBSD 11.2-RELEASE amd64 % exit exit Script done on Sun Jul 8 08:24:20 2018

Edit Command Before Executing

Sometimes you have long multi-line command to execute, so often it is crafted in you favorite ${EDITOR} and then pasted into the terminal. To omit copying and pasting yo may want to check fc(1) command which serves similar purpose. After you type a command, for example simple ls(1) command, and then you type fc(1) command, then fc(1) will take that ls(1) command into your favorite text editor from ${EDITOR} variable, will allow you to edit it and if you save and exit the that editor, it will execute it.

Lets see how it behave by example.

% ls gfx books download scripts % fc

Now you are taken into the ${EDITOR} which is vi(1) in my case.

1 ls ~ ~ ~ /tmp/zsh999EQ6: unmodified: line 1

Lets made some changes.

1 ls -l \ 2 -h ~ ~ ~ ~ :wq

After you hit [ENTER] it will exit from ${EDITOR} and execute that command.

total 6181 drwxr-xr-x 87 vermaden vermaden 87B 2017.12.18 15:30 books/ drwxr-xr-x 12 vermaden vermaden 12B 2018.06.19 16:02 download/ drwxr-xr-x 19 vermaden vermaden 20B 2018.05.24 11:52 gfx/ drwx------ 12 vermaden vermaden 310B 2018.07.07 03:23 scripts/

You may show that command by pressing [Up] key to check what has been executed.

% ls -l -h

Edit or Just View

When working in multi-admin environment – especially while debugging – one admin may block other admin’s work by using vi(1) – or just their favorite editor to ‘browse’ the file contents. Good practice in that case is using more(1) or less(1) instead of vi(1) , but that frustrates some admins to type vi(1) again if they need to change something.

… and by the way, on FreeBSD more(1) is less(1) 🙂

% uname -spr FreeBSD 11.2-RELEASE amd64 % ls -i `which less` `which more` 492318 /usr/bin/less 492318 /usr/bin/more

A blocked ‘example’ is shown below when the second admin wanted to browse the /etc/rc.conf file while the first one already did that.

# vim /etc/rc.conf E325: ATTENTION Found a swap file by the name "/etc/.rc.conf.swp" owned by: root dated: Sun Jul 8 08:38:35 2018 file name: /etc/rc.conf modified: no user name: root host name: t420s.local process ID: 54219 (still running) While opening file "/etc/rc.conf" dated: Fri Jul 6 00:51:11 2018 (1) Another program may be editing the same file. If this is the case, be careful not to end up with two different instances of the same file when making changes. Quit, or continue with caution. (2) An edit session for this file crashed. If this is the case, use ":recover" or "vim -r /etc/rc.conf" to recover the changes (see ":help recovery"). If you did this already, delete the swap file "/etc/.rc.conf.swp" to avoid this message. Swap file "/etc/.rc.conf.swp" already exists! [O]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort:

This is where less(1) comes handy because of you open a file in it, you do not ‘block’ access to it and if you need to edit something just hi [V] key (small ‘v’ letter). It will open that file in your ${EDITOR} editor and you can make any changes now.

Reset

Last but not least, often when you paste ‘too much’ into the terminal it becomes ‘fragile’ or ‘broken’. To reset it into the ‘stable’ and ‘proper’ state just use the reset(1) command.

% reset

Hope You find it useful, see you at the Part 3 sometime 😉

EOF