Your favourite UNIX-pipe (summary)

Andreas Lampen andy at coma.UUCP
Tue Jul 31 20:32:52 AEST 1990


Hi folks,

several weeks ago, I asked for

	Your most favourite (sophisticated, cryptic, funny) pipe !

I received a lot of them. Thank you all. Here is a list

--------------------------------------------------------------------------

1) Matt Crawford (matt at oddjob.uchicago.edu)

Here's one csh alias I like, although the pipe is not the best part of it. 

alias	ptr	"(" echo set q=PTR ";" echo \!\$:e.\!\$:r:e.\!\$:r:r:e.\!\$:r:r:r.in-addr.arpa ")" "|" nslookup

Here's a script which is one long, fun pipe.  (I wrote it when I was new
to unix and didn't know that sh was better than csh for scripts.)

#! /bin/csh -f
# Script to notify heavy disk users of their sins
# Change the constant at the beginning of the awk command as needed.
#
(/usr/etc/quot -f /dev/rxy0e ; /usr/etc/quot -f /dev/rxy0f ; \
 /usr/etc/quot -f /dev/rxy1e ; /usr/etc/quot -f /dev/rxy1f) | \
 egrep -v 'root|/dev/' | \
 sort -nr | \
 awk '$1 > 8000 { printf "mail -s Disk-Usage %s << EOM\n", $3 ;\
    printf "Your %d files in your home directory are using %d KB.\\n",$2,$1 ;\
    printf "This makes you the number %d disk-hog.\n",NR ;\
    printf "EOM\n" ; }' | \
 csh -sf

2) Ken Yap (ken at cs.rochester.edu)

  One of my favourites for renaming all .pas files to .p (or similar) is

	ls *.pas | sed 's/\(.*)\.pas/mv & \1.p/' | sh

3) Andy Behrens (andyb at coat.com)

The next is part of a shell script that runs multiple copies of
compress in parallel, for rapidly compressing large directories.  (Our
host is a multiprocessor, so this really does save time).  The case
statement probably causes a subshell to be started up, so I should
rewrite it so it will run faster.

    PROGRAM=compress
    PARALLEL=10				# number of processors
    P=`expr $N / $PARALLEL + 1`		# each copy of compress gets $P files

    echo "$files" |
    xargs -n$P | 
    case "$trace" in
       -v)  sed "s/.*/$PROGRAM -v   & 2>\&1 | cat  \&/"; echo wait ;;
       *)   sed "s/.*/$PROGRAM      & 2>\&1        \&/"; echo wait ;;
    esac |
    sh |
    sed 's/-- replace.*//'

4) Frank P. Bresz (..!uunet!ittc!fbresz)

#! /bin/csh -f
#
#	Postport Postscript File Conversion.  TLM
#
#	4/10/89 - modified to make lpr use -s option.  TLM
#
if ($#argv == 0) then
	expand | sed -f /usr/local/bin/postsed | awk -f /usr/local/bin/postawk | lpr -s
else
	cat $argv | expand | sed -f /usr/local/bin/postsed | awk -f /usr/local/bin/postawk | lpr -s
endif

This is postsed
s/\\/\\\\/g
s/[(]/\\(/g
s/[)]/\\)/g

This is postawk
BEGIN { cpage = 0
	newline = 720
	newpage = 0
	print "%!\n%%Pages: (atend)\n%%DocumentFonts: Courier"
	print "%%EndComments\n/docstart save def"
	print "/Courier findfont 11 scalefont setfont\n%%EndProlog" }
{ if (newpage == 0) {
	cpage++
	newpage++
	print "%%Page: \"" cpage "\" " cpage "\n/pagestart save def" } }
{ if ( length($0) != 0 ) {
	{ if ( $0 != "\f" ) {
		printf "(%s) 25. %3d. moveto show\n", $0, newline }
	  else {
		{ if ( newline != 720 ) {
			newline = 64 }
		  else {
			newline += 12 } } } } } }
{ newline -= 12 }
{ if (newline <= 64) {
	newline = 720
	newpage--
	print "pagestart restore\nshowpage" } }
END { { if (newline != 720) {
	print "pagestart restore\nshowpage" } }
	{print "%%Trailer\ndocstart restore\n%%Pages: " cpage } }

5) John M. Blasik (john at mintaka.mlb.semi.harris.com)

	rsh other.sun screendump | screenload

[We had a lot of fun with that, Andy]

6) David Elliott (dce at smsc.sony.com)

There are two cases of pipes that I use a lot.

The first is backquotes, and I only mention it to keep you
honest.  I often do things like

	vi `grep -l pattern *.[ch]`

In general, I use the more typical pipes interactively (you don't
want to deal with sh program type pipes, do you?) in an iterative
way.  For example, a csh session might look like:

	% grep pattern1 *.[ch]
	<too much stuff>
	% !! | grep -v pattern2
	grep pattern1 *.[ch] | grep -v pattern2
	<still too much>
	% !! | grep pattern3
	...

until I finally get the set of lines I was looking for.  This
isn't efficient, but it's conceptually the easiest way to do this,
as having to use egrep with OR'ed patterns takes a lot more
typing.

7) Dick Dunn (rcd at ico.isc.com)

A short pipe sequence I use fairly often is
	whatever-stuff | sort | uniq -c | sort -nr | more
which produces a frequency count (in descending order) of lines produced by
"whatever-stuff".

8) Brian Rice (rice at dg-rtp.dg.com)

Wenn man mehreren Prozessen mit aehnlichen Namen (z.B., "biod") toeten
will, kann er benuetzen:

ps -e | grep biod | grep -v grep | awk '{print $2}' | xargs kill -9

(Mit Berkeley UNIX setzt man "-agx" an die Stelle von "-ef", und
auch "grep -v PID | " vor "xargs" einschaltet.)

9) boyd at necisa.ho.necisa.oz.au

It's not one you'd type on the command line, but it's pretty involved.

case "$1" in
8???????)
	;;

"")
	echo "usage: `basename $0` vaddr" 1>&2
	exit 1
	;;

*)
	echo "`basename $0` \"$1\" is not a valid virtual address." 1>&2
	exit 1
	;;
esac

(
	echo 8i
	(
		addr="`echo "$1" | tr '[a-f]' '[A-F]'`"
		echo "*pc* |0`echo 16i8o${addr}p | dc`|.text"
		nm -vo unix
	) | sed -e '/^etext/s/$/.text/' -e '/\.text$/!d' -e 's/|02//' -e 's/|.*//' -e 's/^/[/' -e 's/  */	]P/' -e 's/$/pc/'
) | dc | sort -n +1 | awk '
BEGIN		{
			addr[1] = 0
			addr[2] = 0
			pc = -1
			symbol = "zero"
		}

$1 == "*pc*"	{
			pc = $2
			next
		}

pc != -1 && $2 > pc	{
			addr[2] = $2
			exit
		}

		{
			symbol = $1
			addr[1] = $2
		}

END		{
			printf("0x%x 0x%x\t%s+0x%x (0x8%07x)\n", addr[1], addr[2], symbol, pc - addr[1], pc)
		}
'

10) Paul Davey (pd at ixi.co.uk)

alias tarcp " (cd \!:1 ; tar cf - . ) | ( cd \!:2 ; tar xf - )"

alias psg 'ps aux | sed -n -e  "/sed -n -e /d\\
				/\!$/p\\
				/TIME COMMAND/p"'

set lsfields = `/bin/ls -ld / | wc -w`
if ( "$lsfields" == "8" ) then
	setenv SYS BSD
else
	setenv SYS SYS5
endif
unset lsfields

11) Charles Geyer (charlie at milton.u.washington.edu)

#! /bin/sh
if test $1 = '-b'
then
  shift
  B='-b'
else
  B=''
fi
if test -f $1.spell
then  sed 's/\\[a-zA-Z]*//g' $1.tex | spell $B | sort | comm -23 - $1.spell
else sed 's/\\[a-zA-Z]*//g' $1.tex | spell $B | more

#! /bin/sh
CODA=">/dev/null 2>&1"          # This is the magic
rhost=$1
shift
options=$*
host=`hostname`.stat.washington.edu
DISP="-display $host":0.0
if test `xhost | grep $rhost | wc -l` -eq 0
then
  xhost $rhost
fi
echo "xterm -n $rhost -ls $options $DISP $CODA &" | rsh $rhost sh

12) Martin Weitzel (martin at mwtech.UUCP)

Consider the classic
example where all files with name *.c should be renamed to *.c.bak.

The first approach does it this way:

	for i in `ls *.c`
	do
		mv $i $i.bak
	done

Besides that it is difficult to invert if run-time performance is an
issue (renaming *.c.bak to *.c commonly requires execution of an
`expr ... : ...` in every cycle of the loop), it has more drawbacks:
The list of names generated by ls *.c can not exceed the limit
of several KByte (excact value depends, but is sufficiently low
to cause problems sometimes) and there are some hassles if you
must take the possibility of "no matching files" into account.

Now, compare this to

	ls | sed -n '/\.c$/s=.*=mv & &.bak=p' | sh

which has none of the above drawbacks. Doing the reverse is
not much more complicated:

	ls | sed -n 's=\(.*\.c\)\.bak$=mv & \1=p' | sh

Furthermore, *very* sophisticated things can be done by tailoring
some shell script "on the fly" (as above with "sed", with "awk",
....  or even with an "echo" from another shell) and piping this
to a shell. As shown above this technique at least will take the
burden of looping away from the shell, because the loop is embedded
now in the method that generates the data ("ls"ing a directory
"cat"ing the contents of a file or whatever).

13) Peter da Silva (peter at ficc.ferranti.com)

[Responding to Martin Weitzel (above)]

I would write

ls *.c | while read i; do mv $i $i.bak; done

Or,

ls *.c | sed 's/\(.*\).c$/& \1.bak/' | while read i j; do mv $i $j; done

This does have a bit of looping overhead, and is a big help when what you
want to do is a bit too complex to put into your sed command:

find . -name *.c -print | while read file
  do
    grep '^something:' $file | while read junk body
      do
	process $file -options $body
	and more stuff
      done
  done

If this can qualify as a single 'pipeline', then I have some real bottlers.

14) Jan Christiaan van Winkel (jc at atcmp.nl)

I once had three big files (just below 1 MB each) that when catenated 
made a uuencoded compressed TAR file. The problem was that on the system 
I work on, the ulimit is set to 1 Mb, i.e. I could not create files larger than 
1 Mb. Therefore I had to use a pipe to un-tar the file, for example something 
like

cat xaa xab xac | uudecode | compress -d | tar xvf -

However, uudecode INSISTS on writing to the file named in the first line.
In this case 'tarfil.Z'. This would create a file larger than
1 Mb. (Okay, I could have used the source of uudecode to change that, but I
wanted to do it quick 'n' dirty).
I used a named pipe with the name tarfil.Z to let uudecode write to.
Thus, the commands became:

cat xaa xab xac | uudecode &
compress -d < tarfil.Z | tar xvf -

Mayby not sophisticated, but it sure hepled me!

15) Mitchell Wyle (wyle at inf.ethz.ch)

tr -cs A-Za-z '\012' | tr A-Z a-z | sort | uniq -c | sort -rn

Try that one in a "high-level" language!

16) Joe Bush (bush at evax.arl.utexas.edu)

	Here is one I concocted to search for key words in include
files:

echo -n "key=";set kw=`line`;find /usr/include/. /sys/. -name \*.h -print | xargs hgrep "$kw" {} 

	I keep a file of such one-liners like the one above (file of
one line pipe-programs is named $HOME/.syscom) and have the following
line in my .cshrc:

alias g 'set j=`cat ${home}/.syscom|wc -l`;source -h ${home}/.syscom; history | tail -"$j"'

	Then when I enter "g" from the keyboard, my csh history
mechanism gets primed for easy execution. I find it quite handy...

17) Bjorn Engsig (bengsig at oracle.nl, bengsig at oracle.com)

Neither sophisticated, cryptic or funny, but often useful:
$ make foo
make: don't know how to make `foo'
$ make -n all | grep foo | sh -x

18) Thomas Truscott (trt at rti.rti.org)

Here is a shell script that has a pipeline in it somewhere.

#! /bin/sh

# you pick a word, e.g. "hangman".
# if antihang guesses "a", the new pattern is ".a...a.".
# if antihang then gueses "t", the new pattern is ".a...a." (no change).
# antihang fails on words not in /usr/dict/words

wordlist=/usr/dict/words
myguess=e	guesses=
while [ "$myguess" ]; do
	guesses=$guesses$myguess
	echo -n "I guess $myguess, new pattern: "
	read pattern
	srchpat=`echo "$pattern" | sed "s/\./[^$guesses]/g"` 
	myguess=`grep "^$srchpat$" $wordlist | \
		sed -e "s/[$guesses]//g" -e 's/\(.\)\(.*\)\1/\1\2/g' -e 's/./&\\
/g' | \
		sort |  uniq -c |  sort -nr | \
		sed -n -e 's/^.*\([^ ]\)$/\1/p' | sed 1q`
done

19) Heiner Marxen (heiner at specs.uucp)

Du sammelst doch Pfeifen :-), also hab' ich mal in meine aliase gesehen.
Unten ein Exerpt meines ".login" (fuer csh).  Interessant ist vielleicht
das alias "wot", es enthaelt eine pipe in `` als Teil einer pipe.
     
# Define macros for symbolic naming of directories
# and fast travelling between them.
     
a hier          set GO'\!:1'=\`/bin/pwd\`
a here          set GO'\!:1'='"`dirs | sed '"'"'s/ .*//'"'"'`"'
a go            echo cd \"\$GO'\!:1'\" \; cd \$GO'\!:1'
a gp            echo pd \"\$GO'\!:1'\" \; pd \$GO'\!:1'
a wo            set \| sed '"/^GO/\\!d;s/^GO//"'
a Wo            wo \| sort +1
a wg            wo \| grep
a wot   wo \| egrep '"  (`dirs|sed '"'"'s/ .*//'"'"'`|`pwd`)"'
a wo.   wo \| egrep '"  (`dirs|sed '"'"'s/ .*//'"'"'`|`pwd`)"'\\$
     
a unhere        unset GO'\!:1'
a hereset       set GO'\!:1'='\!:2'
     
a putgo         set \|  \
                sed "'"'/^GO/\\!d;s/$/"/;s/     /       "/;s/^GO/hereset /'"'"
 \
                \>\! ~/.gosave
a getgo         "if( -e ~/.gosave ) source ~/.gosave"
     
     
Dann noch ein gar nicht so untypischer Fall fuer Kommandos, die mit "sh"
implementiert werden.  Das folgende ist Teil eines lokalen scripts um
unseren Postscript-Laser zu beschicken:
     
     
case $# in
 0)     expand $tab | pr5 -w190 $two -f -l77 $prflags
        ;;
 *)     for f
        do
                t="$two"
                l=`sed -e 68q "$f" | wc -l | sed -e 's/^ *//' -e 's/ .*//'`
                case $l in
                 ? | [1-5]?)    t=""    ;;
                 6?)
                        case `expr $l \<= 67` in
                         1)     t=""    ;;
                        esac
                esac
                expand $tab "$f" | pr5 -w190 $t -f -l77 $prflags -h "$f"
        done
        ;;
esac    | lpscript -s7 -r -o1.0 | lpr -Pps

20) Phil Budne (budd at bu-it.bu.edu)

For seeing if anything of mine is stuck in the mqueue (I call it "mq");

	#!/bin/sh
	# display my items in the mail queue
	if [ $# -gt 0 ]; then
		who=$1
	else
		who=`whoami`
	fi
	echo Pending messages on `hostname` from user $who
	#
	mailq | \
	awk "	BEGIN		{ pr = items = found = 0; } \
		/^AA/		{ if( \$0 ~ /$who/ || \$0 ~ /$who\@\.\*/ ) { \
					pr = 1; found++; } \
				  else { pr = 0; } items++; } \
				{ if( pr ) print } \
		END		{ if( found > 0 ) fm = \"(\" found \" displayed)\";
				  print items \" total \" fm } "

A summation of rwho output (I call it "uz");
	#!/bin/sh
	if tty -s <&1;
	then
	    rwho $* | sed 's/[ 	].*//' | uniq | fmt
	else
	    rwho $* | sed 's/[ 	].*//' | uniq
	fi

A count of users as displayed by "uz" (I call it "uc");
	rwho $* | sed 's/[ 	].*//' | uniq | wc -l

For seeing what batched news is queued for a site (I call it "gq")

	#/bin/sh
	# NOTE! our /usr/spool/news is in /news
	SPOOLDIR=/news
	if [ "$1" -a -f $SPOOLDIR/batch/$1 ]; then
	    sed -e 's@/[0-9].*$@@' \
		-e "s@^$SPOOLDIR/@@" \
		-e 's@/@. at g' < /usr/spool/news/batch/$1 |\
	    sort | uniq -c | sort -rn
	fi

Show most frequently executed commands (I call it "lastfreq");

	lastcomm | sed 's/ .*//' | sort | uniq -c | sort -rn

-- 
----
  Andreas Lampen, Tech. Univ. Berlin
      andy at coma.cs.tu-berlin.de



More information about the Comp.unix.wizards mailing list