On Mon, Oct 23, 2023 at 01:32:08AM +0000, Albretch Mueller wrote:
> On 10/22/23, Andy Smith <a...@strugglers.net> wrote:
> > Most of the points Greg makes to you are matters of correctness, not
> > matters of taste.
> 
>  that you called "matters of correctness" may be "visual things" to
> other people. this is something I see on a daily basis I don't try to
> "correct" my students ways, but help them learn, see things for
> themselves.

Was I not sufficiently clear in my explanations?  Sorry.

Your original post contained this line of code:

    cat "${IFL}" | grep "${DESC_DIR}" | tail -c+$_DESC_DIR

In the interests of learning, let's analyze this line *in full*.  From
left to right:

1) Useless use of cat.  In this particular example, the result is still
   correct.  The code is simply longer and slower than it needs to be.

2) All-caps variable name IFL.  All-caps variable names are reserved, by
   convention, for environment variables (e.g. PATH) and special shell
   variables (e.g. IFS).  I assume your variable IFL stands for "input
   file".  But note how close it is to IFS.  I can easily imagine that
   at some point in the future, if you continue using all-caps variable
   names inappropriately, you might accidentally use one that collides
   with an environment variable or a special shell variable.

   Accidentally overwriting IFS is going to break your scripts faster
   than you can imagine.

3) grep "${DESC_DIR}".  Another all-caps variable name, but I won't repeat
   that point.  $DESC_DIR is being passed to a command that expects a
   regular expression, but in your example, it's a literal string.
   Therefore you should use grep -F.  Or use a regular expression in
   DESC_DIR, but that wouldn't be my preferred choice.

4) The tail command is not correct here.  This is the primary error.
   The tail needs to be replaced to make the script work.  Tail operates
   on whole files, not on each line of input, regardless of what options
   you use.

5) You used the _DESC_DIR variable and the DESC_DIR variable together in
   the same command.  I can only imagine one of them was a typo for the
   other.

6) The _DESC_DIR variable expansion is not quoted.  Assuming that it was
   meant to be DESC_DIR which contains a string with spaces and glob
   characters in it, it *must* be quoted, or else it gets passed as an
   unguessable number of separate arguments.

Those are the actual issues I spotted.  I omitted a few in my previous
post, because I wasn't trying to be fully pedantic.  I am now.

Beyond that, I pointed out (by inference) that the code you wrote was
too *limited*.  If the errors are corrected, it will print the output
that you asked for.  But it can't be extended easily to do anything *more*
than that.

Assuming that you actually wanted to *do* something with each line's
suffix, it makes more sense to include some sort of loop, in which you
can add arbitrary commands to do whatever task is needed.

That's why I replaced the tail with a "while read" loop instead of a
single self-contained command, such as sed, which could have done the
printing task more concisely.

Finally, one might wonder why I used this form:

    while IFS= read -r line; do
        ....
    done < <(grep ...)

instead of the simpler form:

    grep ... |
    while IFS= read -r line; do
        ...
    done

This was another conscious choice to offer more flexibility for extending
the script.  In the simpler form, the while loop is executed in a subshell
(because of the pipeline).  When the loop terminates, any changes made in
the subshell are discarded.  This makes it impossible to set persistent
variables inside the loop, and then use them afterward.

The form that I used, with the process substition <(...), runs the loop
in the main shell process, not in a subshell.  With this form, it's
possible to set variables within the loop, and refer to them afterward.

If you have additional questions, feel free to ask them.

Reply via email to