Subject: Bash Lecture Summary (Revision 4)

From: Shlomi Fish <[email-masked]>
Date: Sat, 18 Nov 2000 17:11:54 +0200 (IST)

Here it is. Please just quote only the relevant parts, so the replies
won't occupy too much space.

Regards,

Summary of sh/Bash Lecture:
===========================

Motivation:
-----------

* Bash is the de-facto shell on Linux.

* One can write and debug complete scripts on one-line of the command prompt.

* Sometimes Bash scripts are faster to write and/or easier to understand
  than the equivalent perl scripts.

* 

Basic Usage:
------------

- Executing simple commands: command name followed by parameters
    Examples: 
        ls
        ls -l
        cp test.pl old_test.pl

- Filename Matching mechanisms:
    * 
    []
    ?
    Examples:
        ls -l *.c
        cp *.c ./bak_dir
        
- Pipeline: explain a little about standard input/standard output, then show
    the following redirection mechanisms:
    |
    <
    Examples:
        ls -l | less
        cat *.c *h | wc -l
        ls -l | grep ^d | wc -l

- The ";" - executing more than one statements in the same batch. A 
    synchronous executions.
    Examples:
        cd ./test_dir ; tar -czvf ../test_dir.tar.gz *
    
- The "(" .. ")" - grouping statements inside a _subshell_ (separate process).
    Examples:
        ( cd ./bin ; ls d* ) > files_in_bin_that_start_with_a_d.txt

- The "{" .. "}" - grouping statement in the same shell (not a separate
  process).
    Examples:
        { cd ./bin ; ls d* } > files_in_bin_that_start_with_a_d.txt

- Using the backslash (with no whitespace afterwards) to split commands across
  several lines. Eases readability:
    Examples:
        cp *.c *.h README Makefile TODO \
            USAGE INSTALL \
                ./bak

- Introducing comments with "#". They start with a # and extend to the end of
  the line.
  
Variables:
----------

- Simple assignment: "=". (note that there cannot be any whitespace before
and after the "=" symbol.)
    Examples:
    A=hello
    B=yellow ; turn=500

- Retrieving the value of a variable using $ or ${} . (not $() !)
    Examples:
        - A=hello
          echo $A
        - VARIABLE=5
          B=${VARIABLE}
          VARIABLE=800
          echo $B
        - A=Y
          Y=80
          echo ${$A}
          
- A little about interpolation: A dollar can appear anywhere. If the shell
  encounters a $ which is not followed by curly brackets ("{" .. "}") it will
  try to interpolate its name from as many characters as it find, even if 
  a variable by that name does not exist. Thus, when in doubt, use the
  "${NAME}" form.

    Examples:
        - A=hello
          echo $Aworld
          # does not print helloworld

- The "${parameter:-defaultvalue}" form enables you to give the expression a 
  default value in case the variable is not assigned.
    Examples:
        -
            #!/bin/bash
            
            ; 
            ; Possibly set A
            B=${A:-not_set}
            ; Check if B is equal to not_set and accordingly do something.
            
- To unset a variable use the "unset" command:
    Examples:
        -
            #!/bin/bash
            A=5
            B=80
            RESULT=400
            echo $A \* $B = $RESULT
            unset A B RESULT

- To display a list of the declared variables and their values, use the "set"
  command without any options. (set is of little use in scripts except for
  debugging purposes).

  Examples:
     -
        A=32482 ; B=932840 ; C=1932840 ; D=890 ; E=hello ; F=world
        unset A E
        set | grep '^[A-F]='

- The "read VARNAME" command reads a line from the standard output and puts 
  it inside the variable "VARNAME". 
    Examples:
        echo "Please enter your name:"
        read NAME
        echo Hello $NAME

    - Note: Be careful not to use "read $VARNAME" when it's not appropriate.
        For example:
            #!/bin/sh
            A=B
            B=A
            read $A
            echo A is $A
            echo B is $B

Quoting, Backslashing and other animals
---------------------------------------

- A backslash before a character denotes an "actual" character. Hence means,
  it cannot be processed by the shell.
    Examples:
        - 
        echo Hello\ \ \ \ \ World        # vs.
        echo Hello     World
        -
        echo good ; echo you        
        echo good \; echo you                    # vs.
        -
        echo \\ - This is a backslash

- Use the double quotes to group strings which include whitespaces and
  keywords:
    Examples:
        echo "Hello   World"          # vs.
        echo Hello    World

    Note: double quotes do interpolation. For example:
        #!/bin/sh
        A=Hello
        echo "$A    world!"
        
- Use the single quotes to group strings which include whitespace, dollars
  and backslashes without doing variable interpolation:
    Examples:
        #!/bin/sh
        A=Hello
        echo '$A    world!'
        echo 'and here's a backslash - \'    # Note that \' is not considered
                                             # an inner single quote.

- Quotes and regular texts can be arbitrarily combined (but not nested !)
    Examples:
        #!/bin/sh
        myvar="young at heart"
        echo "Some pe"ople are "${myvar}".
        echo 'Me, 'included\!

Conditionals, Loops and Program Return Codes
--------------------------------------------

- Use the if statement to specify a conditional. Syntax:
    if <Test Command> ; then
        <If Block>
    elif <Test Command> ; then
        <El-If Block>
        .
        .
        .
    else
        <Else Block>
    fi

    As long as there are semi-colons the commands need not be on separate
    lines. Examples:
    
    -
        #!/bin/sh
        if test -e hello.txt ; then
            echo "hello.txt exists"
        else
            echo "hello.txt does not exist"
        fi
   
   Or the same on the same line:
        
        if test -e hello.txt ; then echo "hello.txt exists" ; else echo \
            "hello.txt does not exist" ; fi

   The latter syntax is useful for on-the-prompt scripting.
   
   -
        read A
        if expr $A \< 100 > /dev/null ; then   
            echo "$A is less than 100"
        fi

        # Note that we need to backslash the < so it won't be hijacked by the
        # shell, and if expr's output is not piped to /dev/null it will appear
        # on the screen

- Use the while loop to repeat a command as long as an expression is met.
    Syntax:
    while <Test Expression> ; do
        <Loop Block>
    done

    Examples:
    - 
        #!/bin/sh
        A=0
        while expr $A \< 100 > /dev/null ; do
            echo $A
            A=`expr $A + 1`    # The backticks can be used to trap the output
                               # of the command.
                               # More on that later.
        done
    
        This program prints the numbers from 0 to 99.

    - 
        #!/bin/sh
        find . -name '*.c' | 
        (while read T ; do
            cp $T $T.bak ;
        done)

        This program backups all the C files. read returns a false value when
        it encounters an EOF.

- Iterate over a group of values (or filenames) using the for command:
    for VARNAME in value1 value2 value3 ... ; do
        <For Block where you can use $VARNAME>
    done
    
    Examples:
    -    
        for I in *.c *.h ; do 
            cp $I $I.bak
        done

- As far as "if" and "while" are concerned a statement is considered true if 
    its return code is 0, and false otherwise. The return code of a program is 
    the return code of its main() function, or what was passed as a parameter
    to exit().

- The statement "true" always returns 0 and the statement "false" always 
    returns 1.

- You can find the return code of the last program ran by using the "$?" 
    variable.

- <Statement 1> && <Statement 2> will execute Statement 2 iff Statement 1 
    returns a true value.

  <Statement 1> || <Statement 2> will execute Statement 2 iff Statement 1
    returns a false value.

  For example:

    (cd hello/ && ls) > hello.files.txt
    
    test -e hello.xcf || {
        echo "hello.xcf does not exist";
        exit
        }
 
- Functions: syntax:
    function hello() {
        ## Body Of Function ##
    }

    Functions are used as simple commands and with the same calling syntax.

Trapping Command Output
-----------------------

- Use the $( ... ) and ` ... ` constructs to trap the output of commands. The
    difference between the two is that `` acts very simliarly to the ""
    quotes, in the fact that it expands variables and so forth. $( ... ) on
    the other hand, acts much like a sub-shell while differing only in the 
    fact that the output of the command is trapped.

    Examples:
        
        A=$(cat hello.txt | grep mystring | head -1)
        
        A=`cat hello.txt | grep mystring | head -1`

        C=`expr $A + $B` # Adds A and B and put the result in C

- Another option is to pipe the command output to a sub-shell or sub-script:
    
    Examples:
    
    - find . -name '*.[ch]' -print | 
        (
        while read T ; 
            do cp $T $T.bak
        done
        )

    - cat hello.txt | head -3 | { read A ; read B ; read C} # Put the 
                            # first three lines of hello.txt in A, B and C.

- You can redirect the standard error to the standard output using the "2>&1"
  consturct. If you wish to put it in a separate file, use "2>". The same can
  be done with other file descriptors assuming they are used by your program.
  (which usually is a bad idea).

  Note: you need to append 2>&1 to the _end_ of the command, otherwise
  something entirely different will occur.

  Note: a shorthand for "make > hello.txt 2>&1" is "make &> hello.txt".

- 

	Shlomi Fish

----------------------------------------------------------------------
Shlomi Fish        [email-masked] 
Home Page:         http://t2.technion.ac.il/~shlomif/
Home E-mail:       [email-masked]

The prefix "God Said" has the extraordinary logical property of 
converting any statement that follows it into a true one.

---

From: Moshe Zadka <[email-masked]>
Date: Sat, 18 Nov 2000 22:33:51 +0200 (IST)

>         ls -l | grep ^d | wc -l

You didn't say why you wanted this, but I assume you're going to present
it as a program that "counts the number directories". It doesn't.

moshez@darjeeling:~/prog/src$ python
Python 1.5.2 (#0, Apr  3 2000, 14:46:48)  [GCC 2.95.2 20000313 (Debian
GNU/Linux)] on linux2
Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
>>> import os
>>> os.mkdir("will_delete")
>>> open("will_delete/hello\nd", 'w')
moshez@darjeeling:~/prog/src$ cd will_delete/
moshez@darjeeling:~/prog/src/will_delete$ ls -l |grep ^d|wc -l
      1

I'd try not to have bugs in example programs.

--
Moshe Zadka <[email-masked]> -- 95855124
http://advogato.org/person/moshez

---

From: Shlomi Fish <[email-masked]>
Date: Sun, 19 Nov 2000 09:51:12 +0200 (IST)

> I'd try not to have bugs in example programs.

Do you mean to say you have created a filename that contains the newline
character. I didn't even think it was possible. In any case that's a very
unusual case, so I think my code works 99% of the time.

Of course the more accurate code would be:
NUM_DIRS=0
for I in * ; do
	if [ -d "$I" ] ; then
		NUM_DIRS=`expr $NUM_DIRS + 1`
	fi
done
echo $NUM_DIRS

Regards,

	Shlomi Fish
 
> To unsubscribe from this group, send an email to:
> [email-masked]
> 
> 
> 
>

---

From: Moshe Zadka <[email-masked]>
Date: Sun, 19 Nov 2000 10:25:44 +0200 (IST)

On Sun, 19 Nov 2000, Shlomi Fish wrote:

> character. I didn't even think it was possible.

Then you better brush up on your UNIX skills. There are only two
characters that are illegal in UNIX filenames.

> In any case that's a very
> unusual case

It won't be when people start using tools like Nautilus to create files.

> , so I think my code works 99% of the time.

You have statistics to back it up, I assume? Or is this on of the 96.38%
of statistics which are made up on the spot?

> 		NUM_DIRS=`expr $NUM_DIRS + 1`

I'd benchmark this code on a directory with a 1000 files. You're spawning
a process per file here, you know.
Here's short, accurate and efficient code:

python -c 'import os;print len(filter(os.path.isfile, os.listdir(".")))'

This one also has the advantage that it counts dot-directories. It's 
an exercise to the reader how to make it not include dot-directories.

There was a thread in here, not so long ago, about "using the right tool
for the job". Well, here's an addendum: if takes 3 times as long code to
do it, 10 times as long to execute, and still has weird bugs, maybe it's
not the right tool for the job. Python and Perl (and possible Tcl, Ruby
and Scsh) are the right tools for the job. Heck, even C is probably
better; it would be a bit longer, but at least maintainable and
straightforward.

---

From: Shlomi Fish <[email-masked]>
Date: Sun, 19 Nov 2000 10:48:18 +0200 (IST)

> characters that are illegal in UNIX filenames.

Aren't they / and \?

> It won't be when people start using tools like Nautilus to create files.

Why, does Nautilus actually allow people to have filenames that occupy
more than a one line?

> of statistics which are made up on the spot?

Let's say, that in all the years of using UNIX I never encountered a file
that contained a newline character.

> better; it would be a bit longer, but at least maintainable and

For most practical purposes I'll go with the ls -l | grep ^d | wc -l
scheme. And to hell with filenames that contain newlines.

Regards,

	Shlomi Fish

---

From: Omer Mussaev <[email-masked]>
Date: Sun, 19 Nov 2000 12:17:37 +0200

<<

> - To unset a variable use the "unset" command:

local? i.e

A=1 ;B=2
foo()
{
    local B
    B=3 ; A=4
    echo "in foo: $A $B"
}
echo "before foo: $A $B"
foo
echo "after foo: $A $B"

>         echo "Please enter your name:"

in case input contains more tokens than variables passed to read, the last
variable will contain all the
reaminders, i.e
read first rest
(user enters A B C D)
echo first
(echoes A)
echo rest
(echoes B C D)

-

>             A=`expr $A + 1`    # The backticks can be used to trap the output

$(( )) arithmetics?

>         This program prints the numbers from 0 to 99.

do you need that subprocess? they will ask.

>     - find . -name '*.[ch]' -print |

again.

>   (which usually is a bad idea).

ls -l /proc/$$/fd  on linux will show all file descriptors currently open.

>   something entirely different will occur.

The proper explanation should be something like that:
"A file descriptor (an int) is an offset of stream pointer in stream pointer
array.
When you do 2>&1 it is translated to:

&stdin + 2 = *(&stdin +1)
If you do that redirection before you chgange the value of &stdin + 1,
the slot in stream pointer array  will remember the old value!!!
Therefore, you should know what you are doing. "

---

From: Omer Mussaev <[email-masked]>
Date: Sun, 19 Nov 2000 12:30:38 +0200

> python -c 'import os;print len(filter(os.path.isfile, os.listdir(".")))'

Efficient? You do rally mean that converting the inode into
list of strings and than firing up a monstrous interpreter just to
know what is the length of that string, and firing up stat on EACH one
(just a hint: stat is kernel call) is efficient? Now take into account
time needed to learn Python and then, you call that efficient?

You have to brush up your unix skills, Moshe.
You  have to brush up your unix skills. Moshe.
#ifdef FLAME
YOU HAVE TO KNOW WHAT YOU ARE TALKING ABOUT BEFORE YOU DO!!!!
#else
hm. sorry. No intention to insult.
#error
#endif

well, the efficient solution is:

stat . | awk -F':' '/Links/ {print $4 -2 }'

---

From: Moshe Zadka <[email-masked]>
Date: Sun, 19 Nov 2000 17:00:35 +0200 (IST)

> > characters that are illegal in UNIX filenames.

[moshez@jabotinsky will_delete]$ python
Python 1.5.2 (#1, Feb  1 2000, 16:32:16)  [GCC egcs-2.91.66 19990314/Linux
(egcs- on linux-i386
Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
>>> open("\\", 'w')
<open file '\', mode 'w' at 80c84f0>
[moshez@jabotinsky will_delete]$ ls
\

Are you sure you're qualified?

> Why, does Nautilus actually allow people to have filenames that occupy

I think so.
Otherwise, it will.

> scheme. And to hell with filenames that contain newlines.

Well, I usually try not to advocate using software with bugs. Or
do you think Microsoftish "to hell with computer that should run
for a year without a reboot" is justified too?

---

From: Omer Mussaev <[email-masked]>
Date: Sun, 19 Nov 2000 16:33:44 +0200

I had made a mistake in my previous post.
The vesrion provided will take into account ALL entities as well.

The proper O(1) implementation would be:

printf %d\n $(($(echo */ .*/|wc -w)-2))

Or something like that

---

From: Adi Stav <[email-masked]>
Date: Sun, 19 Nov 2000 17:55:29 +0200

> for a year without a reboot" is justified too?

The Unix approach is to work towards the 90%. A script that cannot
handle a filename with a newline in it is just fine in Unix because
you cannot find such a file in the real world, and anyone who creates
such a file is asking for trouble (or flames, in Nautilus'
hypothetical case). On an MIT-designed system this would have been
unacceptable, but this is a shell lecture, so I guess its ok.

BTW, GNU tar has a -print0 option to seperate the filenames with nulls
instead of newlines, for this exact reason (RMS is from MIT, hehe).

	- Adi Stav

---

From: Moshe Zadka <[email-masked]>
Date: Sun, 19 Nov 2000 18:18:37 +0200 (IST)

> printf %d\n $(($(echo */ .*/|wc -w)-2))

But you're making the same mistake Shlomi made. (Actually, a worse one
since you'll crash and burn when a directory name contains a space).

If we keep doing this stuff, then Miguel is right when he says that
UNIX sucks.
--
Moshe Zadka <[email-masked]> -- 95855124
http://advogato.org/person/moshez

---

From: Moshe Zadka <[email-masked]>
Date: Sun, 19 Nov 2000 18:35:41 +0200 (IST)

On Sun, 19 Nov 2000, Omer Mussaev wrote:

> (just a hint: stat is kernel call) is efficient?

Well, the "list of strings, stat" is a non-issue: ls -l does that to.
Firing up that monstrous interpreter is O(1) compared to the O(n) of
the rest of the algorithm, so it's a non-issue too. 

Hence, my solution was more efficient then Shlomi's because I optimized
the inner loop. It was also correct.

> Now take into account

Oh yes. Oh YES! I think the time I spent learning Python was the most
efficient time I spent. The time I spent learning sh programming is
pretty much wasted these days.
 
> stat . | awk -F':' '/Links/ {print $4 -2 }'

It's probably very efficient. However:

moshez@darjeeling:~$ stat
bash: stat: command not found
moshez@darjeeling:~$

darjeeling is my home computer, which sports a fairly rich installation
of Debian woody. I could not find "stat" on the Solaris box I'm logged
in into, but it's not very well maintained, so it might work on a good
Solaris box: I don't know.

Perhaps a better thing is to work on Guile-Scsh so that we won't
have to "launch" the interpreter: it will already be running.
--
Moshe Zadka <[email-masked]> -- 95855124
http://advogato.org/person/moshez

---

From: Omer Mussaev <[email-masked]>
Date: Sun, 19 Nov 2000 20:19:00 +0200

> the rest of the algorithm, so it's a non-issue too.

Well, I think I do not know alorithms well...or do not understand why is it more

useful to use more efficient algorythm just to produce less efficient
solution...
On my system it took
5 times longer for python version to tell me that there are 0 directories
in /usr/doc, than printf version, which took 0.05 sec of real time.
And btw, there are 402 directories in /usr/doc, and that what printf version
told me.

> the inner loop. It was also correct.

Ok, that means that I have 0 directories in /usr/doc.
I think that I would not understand the proof of correctness...

> pretty much wasted these days.

Please recieve my humble apologies. I should not flame you.

---

From: "Nadav Har'El" <[email-masked]>
Date: Sun, 19 Nov 2000 23:04:52 +0200

On Sun, Nov 19, 2000, Moshe Zadka wrote about "Re: [hackers-il] Bash Lecture Summary (Revision 4)":
>..
>....

The only process he's invoking is the "expr", which he can easily get rid
of, by using the let command available in ksh-based shells (like bash and
zsh):
	let NUM_DIRS++

This way, the above program runs *no* processes (echo and '[' are builtins
in bash and zsh), and is just as efficient as your python example. Which
brings up the point again. So your criticism of the shell, and saying it
doesn't fit for this job is unfair - it fits perfectly.

By the way, zsh also has a way to get all files, including dots filts: you
simply replay "*" by "*(D)".

-- 
Nadav Har'El                        |     Sunday, Nov 19 2000, 22 Heshvan 5761
[email-masked]             |-----------------------------------------
Phone: +972-53-245868, ICQ 13349191 |What's the difference between roast beef
http://nadav.harel.org.il           |and pea soup? Anyone can roast beef.

---

From: "Nadav Har'El" <[email-masked]>
Date: Sun, 19 Nov 2000 23:22:26 +0200

> characters that are illegal in UNIX filenames.

In theory, this is true (for those who didn't figure out which, the answer
is the "/" character and the null character). However, in reality, using
other characters is also asking for trouble. In the past the space character
was problematic (a lot of programs split the file's name and thought it was
two files), but the situation has improved. Using shell meta-characters
(\,",',|,&,* etc.) can be dangerous if you don't quote them correctly (zsh
does that automatically for you when you use completion). And putting a
newline in a file's name is the worse - many tools like ls, find, tar, etc.,
normally assume that files are listed one on each line.

So yes, putting a newline in a filename in Unix is perfectly legal. But
if you'd do it, you'll be doing the same as Bruce Willis in Die Hard 3
(I think) carrying a "I Hate Niggers" sign in Harlem - you'll be asking
for trouble.

-- 
Nadav Har'El                        |     Sunday, Nov 19 2000, 22 Heshvan 5761
[email-masked]             |-----------------------------------------
Phone: +972-53-245868, ICQ 13349191 |Bureaucracy, n: A method for
http://nadav.harel.org.il           |transforming energy into solid waste.

---

From: "Nadav Har'El" <[email-masked]>
Date: Sun, 19 Nov 2000 23:33:16 +0200

> stat . | awk -F':' '/Links/ {print $4 -2 }'

There's one thing you have to watch out for when using this solution: the
fact that directories contain 2 fewer subdirectories than their hard link
count is only true on filesystems that follow Unix conventions. It may not
be true on CD-ROMs, MS-DOS filesystems, and file systems like that, and is
also not true on parts of the /proc filesystem. See the "-noleaf" option in
the find(1) manual, for more info on this.

-- 
Nadav Har'El                        |     Sunday, Nov 19 2000, 22 Heshvan 5761
[email-masked]             |-----------------------------------------
Phone: +972-53-245868, ICQ 13349191 |If God is watching us, the least we can
http://nadav.harel.org.il           |do is be entertaining.

---

From: Moshe Zadka <[email-masked]>
Date: Mon, 20 Nov 2000 00:07:28 +0200 (IST)

> normally assume that files are listed one on each line.

ls, find and tar all work perfectly with any characters. Especially if
you use -print0 when using find. Any program that can't deal with 
a file with metacharacters in it has a bug. As you can now have a pure
free software operating system, you can fix that bug. I'm sure that
if you send the patch to the author, he'll thank you. I fail to see
why you people consider bugs to be acceptable. 

> (I think) carrying a "I Hate Niggers" sign in Harlem - you'll be asking

While comparing carrying "I Hate Niggers" sign to putting \ in your 
file's name is good, comparing UNIX to Harlem is superb! It is ready
to pounce on you for the first sign of weakness, without mercy. 
Let's get rid of the crime -- IOW, fix the bugs which makes the
whole world cry (correctly) "UNIX SUX!".

---

From: "Nadav Har'El" <[email-masked]>
Date: Mon, 20 Nov 2000 09:57:37 +0200

> why you people consider bugs to be acceptable. 

You should also consider the human-interface issue. I've been asked literally
dozens of times by Unix newbies questions like "I have a file named '-* hello'
and I've been trying to remove it for a year without success". Sure, there
are several ways to fix this "bug"
  1. have 'ls' quote shell meta-characters (but for which shell?) and
     non-printable characters (I think it already does this! Doesn't it also
     do it for a newline??), and perhaps add '--' before a file that starts
     with '-'.
  2. Have the shell ignore metacharacters in chosen commands (e.g., rm) or
     quote them when doing completion - both of these are available in zsh, but
     almost nobody is aware of them.
  3. Do away with the shell, and have a graphical interface where you click
     on a file name to delete it, irregardless of the special characters in the
     file name.

Which fix do you recommend? I think they are all flawed. Or do you have
another one in mind?

-- 
Nadav Har'El                        |     Monday, Nov 20 2000, 22 Heshvan 5761
[email-masked]             |-----------------------------------------
Phone: +972-53-245868, ICQ 13349191 |If you drink, don't park; Accidents
http://nadav.harel.org.il           |cause people.

---

From: Moshe Zadka <[email-masked]>
Date: Mon, 20 Nov 2000 10:21:44 +0200 (IST)

On Mon, 20 Nov 2000, Nadav Har'El wrote:

> You should also consider the human-interface issue.

No I shouldn't. I'm a hacker. So are you. Human interface issues should be
left to human interface specialists. That's why prograns I write are
usually built as a library+thin interface -- so a good human interface can
be built on top. Now, good user interfaces used to come from Apple. I have
high hopes new good user interfaces will come from Eazel, which will make
this whole "I have a file named '-* hello'" issue mute.

> I've been asked literally

This isn't a bug -- it's a documented feature. 

> Which fix do you recommend? 

I don't tend to create many files with metachars. But I do try to make
sure my programs work with such files. (One of my programs don't -- but
it's not alpha yet)

> I think they are all flawed. Or do you have
> another one in mind?

In a word, kill the traditional UNIX shell and use something like Scsh
with really good completion. As a long term solution, kill UNIX.

---

From: Adi Stav <[email-masked]>
Date: Mon, 20 Nov 2000 11:35:51 +0200

>      do it for a newline??), and perhaps add '--' before a file that starts

Better yet: add an ls option to simply 'quote' all filenames, and add
a relative pathname in their beginning, i.e. './filename' or
whatever. Much less kludgy.

>      almost nobody is aware of them.

Shell metacharacters are non-issue in pathname expansion, or in
completion. Shells quotes them by themselves. But filename that begin
with a dash will screw things up nevertheless. All that needs to be
done IMO is to have pathname expansion and completion add a relative
pathname before filenames that begin with a dash.

Backticking will also fail. Maybe we need an alternative that works
with null-separated strings, for find -print0 and similar commands?

>      on a file name to delete it, irregardless of the special characters in the

When they pry my keyboard out of my cold, dead hands :)

> Which fix do you recommend? I think they are all flawed. Or do you have

Teach users to './quote' any file they have trouble with -- this will
always work, and is straightforward. I can't see a good way to
transparently turn off substitution and expansion without also turning
off all of the shell's advanteges :(

	- Adi Stav