Project

General

Profile

Shell commands

bash

Debugging: Printing out data

echo "BASH_SOURCE=[${BASH_SOURCE[@]}]" "BASH_ARGV=[${BASH_ARGV[@]}]" "\$0=[$0]" "\$@=[$@]" >&2

1st element of a list

echo "$(set -- *.ext; echo "$1")" 

Waiting for a process

while test -e /proc/<PID>; do sleep 60; done; <commands>

A process putting itself in the background

if test -n "$in_background"; then # running in background
    unset in_background
else # run in background
    export in_background=1
    "$0" "$@" &
    echo "Running $0 in background as process $!" >&2
    exit
fi

svn

Checking diffs

  1. Moved files:
    1. st|grep ^A
    2. Remove the A prefixes, svn di the result, and check that there are no changes
  2. Deleted files:
    1. st|grep ^D
  3. Changed files:
    1. st|grep ^M
    2. svn di each changed file

Makefiles

Debugging: Printing out data

$(error $(var))

ed

substitution

echo $'1\n,s/a/b/\nwq'|ed --loose-exit-status --verbose file

fifos

  • as long as a fifo has >= 1 reader, the writer will not receive SIGPIPE
  • if a fifo/tty has > 1 reader, they will compete for who reads from the pipe buffer
    • for this reason, when a new reader connects, it must then disconnect the existing reader to avoid competing for reads
      • to do this, use SIGHUP in addition to SIGTERM because some processes (e.g. bash -i) ignore SIGTERM
      • the existing reader must be disconnected after connecting so that the fifo always has >= 1 reader

fifo pairs

                terminal end          shell end
             +---------------------------------------+
shell input: | >shell_in_fifo  ----- <shell_in_fifo  |
             +---------------------------------------+

             +---------------------------------------+
shell output:| <shell_out_fifo ----- >shell_out_fifo |
             +---------------------------------------+

ttys

  • the only reason to use a tty pair rather than a fifo pair is to make the shell (and processes it invokes) think it its input/output is from a terminal (i.e. isatty() returns true)
    • some commands (e.g. rsync) will change their output depending on whether their stdout is to a terminal, in order to avoid outputting escape sequences to a log file
                terminal end              shell end
             +--------------------+   +-----------------+
shell input: | >tty_terminal_end  |   |  <tty_shell_end |
             |                  \ |   | /               |
             |                   =|===|=                |
             |                  / |   | \               |
shell output:| <tty_terminal_end  |   |  >tty_shell_end |
             +--------------------+   +-----------------+
  • the terminal end is used by the terminal program (e.g. sshd, Terminal.app) to communicate with the shell.
    it is not visible to the shell via tty.
  • ttys are unusual in that the same tty file will go to different places when read from and written to

Unix

  • tty_terminal_end is /dev/pty# or /dev/ptmx _1
  • tty_shell_end is /dev/tty# or /dev/pts/# _1

1 `man pty` > FILES
.

persistent shells

  • this is similar to the screen command, but uses the terminal's own scrollback
    • when a new reader connects, it will receive any buffered scrollback that the previous reader had not yet read

run a persistent shell

tail -f <shell_in|shell... 2>&1|SIGPIPE_ignoring_cat >shell_out
    # `tail -f` ignores EOF when a writer disconnects
  • SIGPIPE_ignoring_cat runs cat -u but ignores SIGPIPE when a reader disconnects, and instead retries cat -u until a new reader is connected
    • -u avoids blocking until an entire chunk of input is available
    • after the initial SIGPIPE, cat -u will block if there is no reader on shell_out. for this reason, the first write to shell_out needs to be done manually (using read/echo) and timed out. upon timeout, input needs to be flushed to /dev/null for a period of time before retrying, to ensure that the shell's output buffer is always empty. (this allows the shell to run unblocked, even when there is no reader to receive its output.) upon success, writes can continue with cat -u (under the assumption that the reader will read all input promptly and not block the shell).
    • upon SIGPIPE, cat -u will discard whatever data it most recently tried to write. this is not necessarily a problem, because data will be discarded anyway while no reader is connected (see above).

with reconnect scrollback

  • SIGPIPE_ignoring_cat can also print the last n lines of output when a new reader connects (in case these lines were lost by the previous reader when it disconnected)
    • it would use an additional reread buffer for this, which is separate from any pipe buffer used by the cat functionality
    • the reread buffer would reset itself to its beginning every time SIGPIPE is received, so that the scrollback is always echoed first
    • however, if a circular pipe buffer is used, a reread buffer could instead use an iterator over the circular buffer that's separate from its start pointer
      • the reread buffer would advance the start pointer by the same # lines read by the read iterator
        (unless the reread buffer had not yet filled up, in which case it would not change the start pointer)

patch into a persistent shell

cat >shell_in & cat <shell_out; kill %
  • when using ttys, you must use the terminal end rather than the shell end output by tty