Introduction
Archive-name: unix-faq/faq/part3
Version: $Id: part3,v 2.9 1996/06/11 13:07:56 tmatimar Exp $
These seven articles contain the answers to some Frequently Asked
Questions often seen in comp.unix.questions and comp.unix.shell.
Please don't ask these questions again, they've been answered plenty
of times already - and please don't flame someone just because they may
not have read this particular posting. Thank you.
This collection of documents is Copyright (c) 1994, Ted Timar, except
Part 6, which is Copyright (c) 1994, Pierre Lewis and Ted Timar.
All rights reserved. Permission to distribute the collection is
hereby granted providing that distribution is electronic, no money
is involved, reasonable attempts are made to use the latest version
and all credits and this copyright notice are maintained.
Other requests for distribution will be considered. All reasonable
requests will be granted.
All information here has been contributed with good intentions, but
none of it is guaranteed either by the contributors or myself to be
accurate. The users of this information take all responsibility for
any damage that may occur.
Many FAQs, including this one, are available on the archive site
rtfm.mit.edu in the directory pub/usenet/news.answers.
The name under which a FAQ is archived appears in the "Archive-Name:"
line at the top of the article. This FAQ is archived as
"unix-faq/faq/part[1-7]".
These articles are divided approximately as follows:
1.*) General questions.
2.*) Relatively basic questions, likely to be asked by beginners.
3.*) Intermediate questions.
4.*) Advanced questions, likely to be asked by people who thought
they already knew all of the answers.
5.*) Questions pertaining to the various shells, and the differences.
6.*) An overview of Unix variants.
7.*) An comparison of configuration management systems (RCS, SCCS).
This article includes answers to:
3.1) How do I find the creation time of a file?
3.2) How do I use "rsh" without having the rsh hang around
until the remote command has completed?
3.3) How do I truncate a file?
3.4) Why doesn't find's "{}" symbol do what I want?
3.5) How do I set the permissions on a symbolic link?
3.6) How do I "undelete" a file?
3.7) How can a process detect if it's running in the background?
3.8) Why doesn't redirecting a loop work as intended? (Bourne shell)
3.9) How do I run 'passwd', 'ftp', 'telnet', 'tip' and other interactive
programs from a shell script or in the background?
3.10) How do I find the process ID of a program with a particular
name from inside a shell script or C program?
3.11) How do I check the exit status of a remote command
executed via "rsh" ?
3.12) Is it possible to pass shell variable settings into an awk program?
3.13) How do I get rid of zombie processes that persevere?
3.14) How do I get lines from a pipe as they are written instead of
only in larger blocks?
3.15) How do I get the date into a filename?
3.16) Why do some scripts start with #! ... ?
If you're looking for the answer to, say, question 3.5, and want to skip
everything else, you can search ahead for the regular expression "^3.5)".
While these are all legitimate questions, they seem to crop up in
comp.unix.questions or comp.unix.shell on an annual basis, usually
followed by plenty of replies (only some of which are correct) and then
a period of griping about how the same questions keep coming up. You
may also like to read the monthly article "Answers to Frequently Asked
Questions" in the newsgroup "news.announce.newusers", which will tell
you what "UNIX" stands for.
With the variety of Unix systems in the world, it's hard to guarantee
that these answers will work everywhere. Read your local manual pages
before trying anything suggested here. If you have suggestions or
corrections for any of these answers, please send them to to
[email protected].
How do I find the creation time of a file?
Date: Thu Mar 18 17:16:55 EST 1993
3.1) How do I find the creation time of a file?
You can't - it isn't stored anywhere. Files have a last-modified
time (shown by "ls -l"), a last-accessed time (shown by "ls -lu")
and an inode change time (shown by "ls -lc"). The latter is often
referred to as the "creation time" - even in some man pages -
but that's wrong; it's also set by such operations as mv, ln,
chmod, chown and chgrp.
The man page for "stat(2)" discusses this.
How do I use "rsh" without having the rsh hang around ... ?
Date: Thu Mar 18 17:16:55 EST 1993
3.2) How do I use "rsh" without having the rsh hang around until the
remote command has completed?
(See note in question 2.7 about what "rsh" we're talking about.)
The obvious answers fail:
rsh machine command &
or rsh machine 'command &'
For instance, try doing rsh machine 'sleep 60 &' and you'll see
that the 'rsh' won't exit right away. It will wait 60 seconds
until the remote 'sleep' command finishes, even though that
command was started in the background on the remote machine. So
how do you get the 'rsh' to exit immediately after the 'sleep' is
started?
The solution - if you use csh on the remote machine:
rsh machine -n 'command >&/dev/null </dev/null &'
If you use sh on the remote machine:
rsh machine -n 'command >/dev/null 2>&1 </dev/null &'
Why? "-n" attaches rsh's stdin to /dev/null so you could run the
complete rsh command in the background on the LOCAL machine.
Thus "-n" is equivalent to another specific "< /dev/null".
Furthermore, the input/output redirections on the REMOTE machine
(inside the single quotes) ensure that rsh thinks the session can
be terminated (there's no data flow any more.)
Note: The file that you redirect to/from on the remote machine
doesn't have to be /dev/null; any ordinary file will do.
In many cases, various parts of these complicated commands
aren't necessary.
How do I truncate a file?
Date: Mon, 27 Mar 1995 18:09:10 -0500
3.3) How do I truncate a file?
The BSD function ftruncate() sets the length of a file.
(But not all versions behave identically.) Other Unix variants
all seem to support some version of truncation as well.
For systems which support the ftruncate function, there are
three known behaviours:
BSD 4.2 - Ultrix, SGI, LynxOS
- truncation doesn't grow file
- truncation doesn't move file pointer
BSD 4.3 - SunOS, Solaris, OSF/1, HP/UX, Amiga
- truncation can grow file
- truncation doesn't move file pointer
Cray - UniCOS 7, UniCOS 8
- truncation doesn't grow file
- truncation changes file pointer
Other systems come in four varieties:
F_CHSIZE - Only SCO
- some systems define F_CHSIZE but don't support it
- behaves like BSD 4.3
F_FREESP - Only Interative Unix
- some systems (eg. Interactive Unix) define F_FREESP but
don't support it
- behaves like BSD 4.3
chsize() - QNX and SCO
- some systems (eg. Interactive Unix) have chsize() but
don't support it
- behaves like BSD 4.3
nothing - no known systems
- there will be systems that don't support truncate at all
Moderator's Note: I grabbed the functions below a few years back.
I can no longer identify the original author.
S. Spencer Sun <[email protected]> has also
contributed a version for F_FREESP.
functions for each non-native ftruncate follow
/* ftruncate emulations that work on some System V's.
This file is in the public domain. */
#include
#include
#ifdef F_CHSIZE
int
ftruncate (fd, length)
int fd;
off_t length;
{
return fcntl (fd, F_CHSIZE, length);
}
#else
#ifdef F_FREESP
/* The following function was written by
[email protected] (William Kucharski) */
#include
#include
#include
int
ftruncate (fd, length)
int fd;
off_t length;
{
struct flock fl;
struct stat filebuf;
if (fstat (fd, &filebuf) < 0)
return -1;
if (filebuf.st_size < length)
{
/* Extend file length. */
if (lseek (fd, (length - 1), SEEK_SET) < 0)
return -1;
/* Write a "0" byte. */
if (write (fd, "", 1) != 1)
return -1;
}
else
{
/* Truncate length. */
fl.l_whence = 0;
fl.l_len = 0;
fl.l_start = length;
fl.l_type = F_WRLCK; /* Write lock on file space. */
/* This relies on the UNDOCUMENTED F_FREESP argument to
fcntl, which truncates the file so that it ends at the
position indicated by fl.l_start.
Will minor miracles never cease? */
if (fcntl (fd, F_FREESP, &fl) < 0)
return -1;
}
return 0;
}
#else
int
ftruncate (fd, length)
int fd;
off_t length;
{
return chsize (fd, length);
}
#endif
#endif
Why doesn't find's "{}" symbol do what I want?
Date: Thu Mar 18 17:16:55 EST 1993
3.4) Why doesn't find's "{}" symbol do what I want?
"find" has a -exec option that will execute a particular command
on all the selected files. Find will replace any "{}" it sees
with the name of the file currently under consideration.
So, some day you might try to use "find" to run a command on
every file, one directory at a time. You might try this:
find /path -type d -exec command {}/\* \;
hoping that find will execute, in turn
command directory1/*
command directory2/*
...
Unfortunately, find only expands the "{}" token when it appears
by itself. Find will leave anything else like "{}/*" alone, so
instead of doing what you want, it will do
command {}/*
command {}/*
...
once for each directory. This might be a bug, it might be a
feature, but we're stuck with the current behaviour.
So how do you get around this? One way would be to write a
trivial little shell script, let's say "./doit", that consists of
command "$1"/*
You could then use
find /path -type d -exec ./doit {} \;
Or if you want to avoid the "./doit" shell script, you can use
find /path -type d -exec sh -c 'command $0/*' {} \;
(This works because within the 'command' of "sh -c 'command' A B C ...",
$0 expands to A, $1 to B, and so on.)
or you can use the construct-a-command-with-sed trick
find /path -type d -print | sed 's:.*:command &/*:' | sh
If all you're trying to do is cut down on the number of times
that "command" is executed, you should see if your system has the
"xargs" command. Xargs reads arguments one line at a time from
the standard input and assembles as many of them as will fit into
one command line. You could use
find /path -print | xargs command
which would result in one or more executions of
command file1 file2 file3 file4 dir1/file1 dir1/file2
Unfortunately this is not a perfectly robust or secure solution.
Xargs expects its input lines to be terminated with newlines, so
it will be confused by files with odd characters such as newlines
in their names.
How do I set the permissions on a symbolic link?
Date: Thu Mar 18 17:16:55 EST 1993
3.5) How do I set the permissions on a symbolic link?
Permissions on a symbolic link don't really mean anything. The
only permissions that count are the permissions on the file that
the link points to.
How do I "undelete" a file?
Date: Thu Mar 18 17:16:55 EST 1993
3.6) How do I "undelete" a file?
Someday, you are going to accidentally type something like
"rm * .foo", and find you just deleted "*" instead of "*.foo".
Consider it a rite of passage.
Of course, any decent systems administrator should be doing
regular backups. Check with your sysadmin to see if a recent
backup copy of your file is available. But if it isn't, read
on.
For all intents and purposes, when you delete a file with "rm" it
is gone. Once you "rm" a file, the system totally forgets which
blocks scattered around the disk were part of your file. Even
worse, the blocks from the file you just deleted are going to be
the first ones taken and scribbled upon when the system needs
more disk space. However, never say never. It is theoretically
possible *if* you shut down the system immediately after the "rm"
to recover portions of the data. However, you had better have a
very wizardly type person at hand with hours or days to spare to
get it all back.
Your first reaction when you "rm" a file by mistake is why not
make a shell alias or procedure which changes "rm" to move files
into a trash bin rather than delete them? That way you can
recover them if you make a mistake, and periodically clean out
your trash bin. Two points: first, this is generally accepted
as a *bad* idea. You will become dependent upon this behaviour
of "rm", and you will find yourself someday on a normal system
where "rm" is really "rm", and you will get yourself in trouble.
Second, you will eventually find that the hassle of dealing with
the disk space and time involved in maintaining the trash bin, it
might be easier just to be a bit more careful with "rm". For
starters, you should look up the "-i" option to "rm" in your
manual.
If you are still undaunted, then here is a possible simple
answer. You can create yourself a "can" command which moves
files into a trashcan directory. In csh(1) you can place the
following commands in the ".login" file in your home directory:
alias can 'mv \!* ~/.trashcan' # junk file(s) to trashcan
alias mtcan 'rm -f ~/.trashcan/*' # irretrievably empty trash
if ( ! -d ~/.trashcan ) mkdir ~/.trashcan # ensure trashcan exists
You might also want to put a:
rm -f ~/.trashcan/*
in the ".logout" file in your home directory to automatically
empty the trash when you log out. (sh and ksh versions are left
as an exercise for the reader.)
MIT's Project Athena has produced a comprehensive
delete/undelete/expunge/purge package, which can serve as a
complete replacement for rm which allows file recovery. This
package was posted to comp.sources.misc (volume 17, issue
023-026)
How can a process detect if it's running in the background?
Date: Thu Mar 18 17:16:55 EST 1993
3.7) How can a process detect if it's running in the background?
First of all: do you want to know if you're running in the
background, or if you're running interactively? If you're
deciding whether or not you should print prompts and the like,
that's probably a better criterion. Check if standard input
is a terminal:
sh: if [ -t 0 ]; then ... fi
C: if(isatty(0)) { ... }
In general, you can't tell if you're running in the background.
The fundamental problem is that different shells and different
versions of UNIX have different notions of what "foreground" and
"background" mean - and on the most common type of system with a
better-defined notion of what they mean, programs can be moved
arbitrarily between foreground and background!
UNIX systems without job control typically put a process into the
background by ignoring SIGINT and SIGQUIT and redirecting the
standard input to "/dev/null"; this is done by the shell.
Shells that support job control, on UNIX systems that support job
control, put a process into the background by giving it a process
group ID different from the process group to which the terminal
belongs. They move it back into the foreground by setting the
terminal's process group ID to that of the process. Shells that
do *not* support job control, on UNIX systems that support job
control, typically do what shells do on systems that don't
support job control.
Why doesn't redirecting a loop work as intended? (Bourne shell)
Date: Thu Mar 18 17:16:55 EST 1993
3.8) Why doesn't redirecting a loop work as intended? (Bourne shell)
Take the following example:
foo=bar
while read line
do
# do something with $line
foo=bletch
done < /etc/passwd
echo "foo is now: $foo"
Despite the assignment ``foo=bletch'' this will print
``foo is now: bar'' in many implementations of the Bourne shell.
Why? Because of the following, often undocumented, feature of
historic Bourne shells: redirecting a control structure (such as
a loop, or an ``if'' statement) causes a subshell to be created,
in which the structure is executed; variables set in that
subshell (like the ``foo=bletch'' assignment) don't affect the
current shell, of course.
The POSIX 1003.2 Shell and Tools Interface standardization
committee forbids the behaviour described above, i.e. in P1003.2
conformant Bourne shells the example will print ``foo is now:
bletch''.
In historic (and P1003.2 conformant) implementations you can use
the following `trick' to get around the redirection problem:
foo=bar
# make file descriptor 9 a duplicate of file descriptor 0 (stdin);
# then connect stdin to /etc/passwd; the original stdin is now
# `remembered' in file descriptor 9; see dup(2) and sh(1)
exec 9<&0 < /etc/passwd
while read line
do
# do something with $line
foo=bletch
done
# make stdin a duplicate of file descriptor 9, i.e. reconnect
# it to the original stdin; then close file descriptor 9
exec 0<&9 9<&-
echo "foo is now: $foo"
This should always print ``foo is now: bletch''.
Right, take the next example:
foo=bar
echo bletch | read foo
echo "foo is now: $foo"
This will print ``foo is now: bar'' in many implementations,
``foo is now: bletch'' in some others. Why? Generally each part
of a pipeline is run in a different subshell; in some
implementations though, the last command in the pipeline is made
an exception: if it is a builtin command like ``read'', the
current shell will execute it, else another subshell is created.
POSIX 1003.2 allows both behaviours so portable scripts cannot
depend on any of them.
What's wrong with having '.' in your $PATH ?
Date: Thu Mar 18 17:16:55 EST 1993
2.13) What's wrong with having '.' in your $PATH ?
A bit of background: the PATH environment variable is a list of
directories separated by colons. When you type a command name
without giving an explicit path (e.g. you type "ls", rather than
"/bin/ls") your shell searches each directory in the PATH list in
order, looking for an executable file by that name, and the shell
will run the first matching program it finds.
One of the directories in the PATH list can be the current
directory "." . It is also permissible to use an empty directory
name in the PATH list to indicate the current directory. Both of
these are equivalent
for csh users:
setenv PATH :/usr/ucb:/bin:/usr/bin
setenv PATH :/usr/ucb:/bin:/usr/bin
for sh or ksh users
PATH=:/usr/ucb:/bin:/usr/bin export PATH
PATH=:/usr/ucb:/bin:/usr/bin export PATH
Having "." somewhere in the PATH is convenient - you can type
"a.out" instead of "./a.out" to run programs in the current
directory. But there's a catch.
Consider what happens in the case where "." is the first entry
in the PATH. Suppose your current directory is a publically-
writable one, such as "/tmp". If there just happens to be a
program named "/tmp/ls" left there by some other user, and you
type "ls" (intending, of course, to run the normal "/bin/ls"
program), your shell will instead run "./ls", the other user's
program. Needless to say, the results of running an unknown
program like this might surprise you.
It's slightly better to have "." at the end of the PATH:
setenv PATH /usr/ucb:/bin:/usr/bin:.
Now if you're in /tmp and you type "ls", the shell will
search /usr/ucb, /bin and /usr/bin for a program named
"ls" before it gets around to looking in ".", and there
is less risk of inadvertently running some other user's
"ls" program. This isn't 100% secure though - if you're
a clumsy typist and some day type "sl -l" instead of "ls -l",
you run the risk of running "./sl", if there is one.
Some "clever" programmer could anticipate common typing
mistakes and leave programs by those names scattered
throughout public directories. Beware.
Many seasoned Unix users get by just fine without having
"." in the PATH at all:
setenv PATH /usr/ucb:/bin:/usr/bin
If you do this, you'll need to type "./program" instead
of "program" to run programs in the current directory, but
the increase in security is probably worth it.
How do I ring the terminal bell during a shell script?
>From: [email protected] (Uwe Waldmann)
Date: Fri, 30 Apr 93 16:33:00 +0200
2.14) How do I ring the terminal bell during a shell script?
The answer depends on your Unix version (or rather on the kind of
"echo" program that is available on your machine).
A BSD-like "echo" uses the "-n" option for suppressing the final
newline and does not understand the octal \nnn notation. Thus
the command is
echo -n '^G'
where ^G means a _literal_ BEL-character (you can produce this in
emacs using "Ctrl-Q Ctrl-G" and in vi using "Ctrl-V Ctrl-G").
A SysV-like "echo" understands the \nnn notation and uses \c to
suppress the final newline, so the answer is:
echo '\007\c'
Why can't I use "talk" to talk with my friend on machine X?
>From: [email protected] (Ted Timar)
Date: Thu Mar 18 17:16:55 EST 1993
2.15) Why can't I use "talk" to talk with my friend on machine X?
Unix has three common "talk" programs, none of which can talk with
any of the others. The "old" talk accounts for the first two types.
This version (often called otalk) did not take "endian" order into
account when talking to other machines. As a consequence, the Vax
version of otalk cannot talk with the Sun version of otalk.
These versions of talk use port 517.
Around 1987, most vendors (except Sun, who took 6 years longer than
any of their competitors) standardized on a new talk (often called
ntalk) which knows about network byte order. This talk works between
all machines that have it. This version of talk uses port 518.
There are now a few talk programs that speak both ntalk and one
version of otalk. The most common of these is called "ytalk".
Why does calendar produce the wrong output?
>From: [email protected] (Ted Timar)
Date: Thu Sep 8 09:45:46 EDT 1994
2.16) Why does calendar produce the wrong output?
Frequently, people find that the output
for the Unix calendar
program, 'cal' produces output that they
do not expect.
The calendar for September 1752 is very
odd:
September 1752
S M Tu W Th F S
1 2 14 15 16
17 18
19 20 21 22 23
24 25
26 27 28 29 30
This is the month in which the US (the entire
British Empire actually)
switched from the Julian to the Gregorian
calendar.
The other common problem people have with
the calendar program is
that they pass it arguments like 'cal 9
94'. This gives the calendar
for September of AD 94, NOT 1994.
------------------------------
End of unix/faq Digest part 2 of 7
**********************************