Find the answer to your Linux question:
Results 1 to 6 of 6
Greetings. I just joined this forum (so new that I have not been able to post an avatar yet.) I recently posted this question on the Ubuntu forum (with a ...
  1. #1
    Just Joined!
    Join Date
    Nov 2011
    Location
    Brooklyn, NY (USA)
    Posts
    4

    Indirect reference works once only

    Greetings.

    I just joined this forum (so new that I have not been able to post an avatar yet.) I recently posted this question on the Ubuntu forum (with a misspelled reference )and got no helpful response. I hope this forum has more daring readers. It ain't short but a complicated question can't be asked in 30 words. OK, Here goes:
    -----------------------------------------------------------
    I have recently started trying to use indirect references in ksh93. That is, when I set variable-b to the name of variable-a and obtain the value of variable-a by dereferencing variable-b. (Sorta like pointers.)

    I have been able to make it work but not in the manner I had expected. I'm hoping someone can point out my flaw.

    Let's start with my "control" script, where I have made no real effort to use the indirect reference.
    Code:
     1 #!/bin/ksh
     2 #
     3 4 one=1
     5 two=2
     6 three=3
     7 four=4
     8 five=5
     9
    10 for DIGIT in one two three four five
    11 do
    12   NUMBER=$DIGIT
    14   echo $DIGIT ${NUMBER}
    15 done
    (The missing line numbers are where I have removed commented code)
    Here is the output of that:
    one one
    two two
    three three
    four four
    five five
    This is very much as expected.

    Now let's declare NUMBER to be an indirect reference:
    Code:
     1 #!/bin/ksh
     2 #
     3 typeset -n NUMBER
     4 one=1
     5 two=2
     6 three=3
     7 four=4
     8 five=5
     9
    10 for DIGIT in one two three four five
    11 do
    12   NUMBER=$DIGIT
    14   echo $DIGIT ${NUMBER}
    15 done
    The output of this attempt is:
    one 1
    two two
    three three
    four four
    five five
    Hey, it worked only the first time! After that it gave me the names I threw into it instead of chasing down the values behind those names.

    OK, what happens if I repeat the typeset command each time around the loop. If I do this I don't need to do it on line 3. Here goes:
    Code:
     1 #!/bin/ksh
     2 #
     3 #typeset -n NUMBER
     4 one=1
     5 two=2
     6 three=3
     7 four=4
     8 five=5
     9
    10 for DIGIT in one two three four five
    11 do
    12   NUMBER=$DIGIT
    13   typeset -n NUMBER=$DIGIT
    14   echo $DIGIT ${NUMBER}
    15 done
    And the output of that is:
    one 1
    two 2
    three 3
    four 4
    five 5
    AHA! THAT'S the output I was looking for! But it annoys me that I should need to repeat the typeset command for every new string name [of a variable] to which I set NUMBER. It looks like one typeset declaration is not enough.

    Is there some way I can use one typeset directive and have it last the duration of the script? BTW, using the nameref directive wasn't any more successful. I was trying to mimic the examples in Bolsky and Korn's book The New KornShell Command And Programming Language (2nd Edition) but the examples there are more on using associative arrays of namerefs. Powerful and useful as those are, my example was trying to keep it simple for my first foray into the use of namerefs.

    Thanks much for advice. This will affect the nature of shell scripts I am planning.
    __________________
    -- Rasputin Paskudniak II (In pursuit of undomesticated, semi-aquatic avians)

  2. #2
    Trusted Penguin Cabhan's Avatar
    Join Date
    Jan 2005
    Location
    Seattle, WA, USA
    Posts
    3,230
    My first advice to you is to use bash, not ksh. ksh is almost never used anymore, and there are not nearly as many resources as there are for bash. bash is essentially the standard shell now, with zsh becoming popular in some circles.

    Anyway, based on the research that I have been able to do, this is basically expected behavior. Unlike, for instance, bash's typeset, ksh's "typeset -n" appears to indicate that THIS ASSIGNMENT is a reference assignment. bash's typeset (and perhaps other ksh typesets, I do not know) sets properties of the variable, not particular assignments, and references use a different syntax.

    So when you say "typeset -n NUMBER=$DIGIT", you are saying "make NUMBER be a reference to DIGIT". But then when you later say "NUMBER=$DIGIT", you are saying "set NUMBER to the value of DIGIT".

    Does this make sense?
    DISTRO=Arch
    Registered Linux User #388732

  3. #3
    drl
    drl is offline
    Linux Engineer drl's Avatar
    Join Date
    Apr 2006
    Location
    Saint Paul, MN, USA / CentOS, Debian, Solaris, SuSE
    Posts
    1,117
    Hi.

    I look at this based on the description:
    A
    nameref is created with the -n attribute of typeset. The value of the
    variable at the time of the typeset command becomes the variable that
    will be referenced whenever the nameref variable is used.
    -- excerpt from man ksh
    which suggests that this is a property of the nameref, but that the action is essentially static -- whatever is the current value of variable will be the name of the variable that will be the value supplied when the nameref is used. From this perspective, the result posted by the OP is what I would expect -- i.e. that the typeset is needed to cause a new value to be set. Perhaps this is a re-phrase of the reply from cabhan, but it seems different to me.

    Minor quibble with:
    Quote Originally Posted by Cabhan
    ... ksh is almost never used anymore ...
    There are many people over at unix.com who would disagree with that statement. Having said that, there probably are more people that use bash than use ksh, making it somewhat more likely to be able to get help with bash as opposed to ksh. The entry at Korn shell - Wikipedia, the free encyclopedia suggests that David Korn still supports it. Development of ksh certainly seems to be slow if not stopped when compared to bash.

    There is an interesting Q and A with Korn at David Korn Tells All - Slashdot

    Best wishes ... cheers, drl
    Welcome - get the most out of the forum by reading forum basics and guidelines: click here.
    90% of questions can be answered by using man pages, Quick Search, Advanced Search, Google search, Wikipedia.
    We look forward to helping you with the challenge of the other 10%.
    ( Mn, 2.6.n, AMD-64 3000+, ASUS A8V Deluxe, 1 GB, SATA + IDE, Matrox G400 AGP )

  4. #4
    drl
    drl is offline
    Linux Engineer drl's Avatar
    Join Date
    Apr 2006
    Location
    Saint Paul, MN, USA / CentOS, Debian, Solaris, SuSE
    Posts
    1,117
    Hi.

    By accident, I noticed this in the ksh man page on nameref:
    If a nameref is used as the index of a for loop, a name
    reference is established for each item in the list.
    which would lead to something like this:
    Code:
    #!/usr/bin/env ksh
    
    # @(#) s1	Demonstrate special case for-loop property of ksh nameref.
    
    # Utility functions: print-as-echo, print-line-with-visual-space, debug.
    # export PATH="/usr/local/bin:/usr/bin:/bin"
    pe() { for _i;do printf "%s" "$_i";done; printf "\n"; }
    pl() { pe;pe "-----" ;pe "$*"; }
    db() { ( printf " db, ";for _i;do printf "%s" "$_i";done;printf "\n" ) >&2 ; }
    db() { : ; }
    C=$HOME/bin/context && [ -f $C ] && . $C
    
    pe
    one=1
    two=2
    three=3
    four=4
    five=5
    
    for DIGIT in one two three four five
    do
      NUMBER=$DIGIT
      echo $DIGIT ${NUMBER}
    done
    
    pe
    nameref DIGIT
    for DIGIT in one two three four five
    do
      NUMBER=$DIGIT
      echo $NUMBER
    done
    
    exit 0
    producing:
    Code:
    % ./s1
    
    Environment: LC_ALL = C, LANG = C
    (Versions displayed with local utility "version")
    OS, ker|rel, machine: Linux, 2.6.26-2-amd64, x86_64
    Distribution        : Debian GNU/Linux 5.0.8 (lenny) 
    ksh 93s+
    
    one one
    two two
    three three
    four four
    five five
    
    1
    2
    3
    4
    5
    Best wishes ... cheers, drl
    Welcome - get the most out of the forum by reading forum basics and guidelines: click here.
    90% of questions can be answered by using man pages, Quick Search, Advanced Search, Google search, Wikipedia.
    We look forward to helping you with the challenge of the other 10%.
    ( Mn, 2.6.n, AMD-64 3000+, ASUS A8V Deluxe, 1 GB, SATA + IDE, Matrox G400 AGP )

  5. #5
    Just Joined!
    Join Date
    Nov 2011
    Location
    Brooklyn, NY (USA)
    Posts
    4
    Dear DRL,

    You have helped me tremendously by noticing that remark stuck in the haystack of the ksh man page. It took me a few minutes of scrolling up and down this thread before I saw the difference between your code and my example #2, where it worked only for the first round of the loop. Otherwise, I will indeed need to use an explicit typedef -n (or nameref). So my question is answered to my satisfaction, if not the perfect manner I was hoping for.

    As to cabhan's suggestion that I switch to bash: Many scripts I have written use the construct:
    <some program that generates many similar lines> | while read A B C D E
    do
    <huge stuff>
    done.

    This works in ksh but barfs at me like an infant sibling in bash. I posted my issue with bash in January on the Ubuntu Forum. So bash is out of my equation. BTW< I am constrained from posting the URL of that thread because I am too new to this forum. However, the thread title is "bash read command not assigning the target variables", originally posted 2011-01-02.

    Now how do I mark this thread "Solved"?

    Again, thanks drl. And cheers back across the pond.

    -- Rasputin Paskudniak (In pursuit of undomesticated, semi-aquatic avians)

  6. #6
    drl
    drl is offline
    Linux Engineer drl's Avatar
    Join Date
    Apr 2006
    Location
    Saint Paul, MN, USA / CentOS, Debian, Solaris, SuSE
    Posts
    1,117
    Hi, rpaskudniak.

    Two comments:

    1) You might want to look over the thread at korn shell variable help for another method of handling lists, namely arrays.

    2) The bash property of creating a separate scope for a pipe-into-loop situation can be avoided by using a special bash syntax. The script below will attempt to perform 2 loops, 1 piping in at the top, the other re-directing from the bottom. The results are for sh, ksh, and bash:
    Code:
    #!/usr/bin/env sh
    
    # @(#) s4	Demonstrate re-direct input at bottom of loop.
    
    # Utility functions: print-as-echo, print-line-with-visual-space, debug.
    # export PATH="/usr/local/bin:/usr/bin:/bin"
    pe() { for _i;do printf "%s" "$_i";done; printf "\n"; }
    pl() { pe;pe "-----" ;pe "$*"; }
    db() { ( printf " db, ";for _i;do printf "%s" "$_i";done;printf "\n" ) >&2 ; }
    db() { : ; }
    C=$HOME/bin/context && [ -f $C ] && . $C
    
    n=0
    lines=0
    pl " Results, pipe into while at top, n = $n, lines = $lines"
    seq 5 | wc -l |
    while read n
    do
      pe " In loop, number of sequences is $n"
      lines=$n
    done
    
    pl " Outside loop, n is $n, lines is $lines"
    
    n=0
    lines=0
    pl " Results, pipe into while at bottom, n = $n, lines = $lines"
    while read n
    do
      pe " In loop, number of sequences is $n"
      lines=$n
    done < <( seq 5 | wc -l )
    
    pl " Outside loop, n is $n, lines = $lines"
    
    exit 0
    producing for sh (linked to bash, but doing things sh-like):
    Code:
    % ./s4
    
    Environment: LC_ALL = C, LANG = C
    (Versions displayed with local utility "version")
    OS, ker|rel, machine: Linux, 2.6.26-2-amd64, x86_64
    Distribution        : Debian GNU/Linux 5.0.8 (lenny) 
    GNU bash, version 3.2.39(1)-release (x86_64-pc-linux-gnu)
    
    -----
     Results, pipe into while at top, n = 0, lines = 0
     In loop, number of sequences is 5
    
    -----
     Outside loop, n is 0, lines is 0
    
    -----
     Results, pipe into while at bottom, n = 0, lines = 0
    ./s4: line 32: syntax error near unexpected token `<'
    ./s4: line 32: `done < <( seq 5 | wc -l )'
    producing with ksh:
    Code:
    % ksh s4
    
    Environment: LC_ALL = C, LANG = C
    (Versions displayed with local utility "version")
    OS, ker|rel, machine: Linux, 2.6.26-2-amd64, x86_64
    Distribution        : Debian GNU/Linux 5.0.8 (lenny) 
    ksh 93s+
    
    -----
     Results, pipe into while at top, n = 0, lines = 0
     In loop, number of sequences is 5
    
    -----
     Outside loop, n is , lines is 5
    
    -----
     Results, pipe into while at bottom, n = 0, lines = 0
    s4: line 27: syntax error at line 32: `<(' unexpected
    noting that ksh does not understand the special sequence, but bash produces:
    Code:
    % bash s4
    
    Environment: LC_ALL = C, LANG = C
    (Versions displayed with local utility "version")
    OS, ker|rel, machine: Linux, 2.6.26-2-amd64, x86_64
    Distribution        : Debian GNU/Linux 5.0.8 (lenny) 
    GNU bash 3.2.39
    
    -----
     Results, pipe into while at top, n = 0, lines = 0
     In loop, number of sequences is 5
    
    -----
     Outside loop, n is 0, lines is 0
    
    -----
     Results, pipe into while at bottom, n = 0, lines = 0
     In loop, number of sequences is 5
    
    -----
     Outside loop, n is , lines = 5
    noting that bash fails on the pipe-in-from-top loop, but succeeds with the special syntax re-directing in from the bottom (spaces in "< <(" are necessary)

    Best wishes ... cheers, drl
    Welcome - get the most out of the forum by reading forum basics and guidelines: click here.
    90% of questions can be answered by using man pages, Quick Search, Advanced Search, Google search, Wikipedia.
    We look forward to helping you with the challenge of the other 10%.
    ( Mn, 2.6.n, AMD-64 3000+, ASUS A8V Deluxe, 1 GB, SATA + IDE, Matrox G400 AGP )

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
...