• Create functional processing pipe (without eval)?

    From Janis Papanagnou@21:1/5 to All on Wed May 7 04:02:13 2025
    I'm pondering about creating a functional processing pipe, depending
    on program parameters, and whether that's possible to achieve without
    using 'eval'.

    Say, the program is called "filter" and may accept 0..N parameters and depending on the set of parameters the respective pipe functionality
    shall be defined like

    filter => cat
    filter p1 => cat | func p1
    filter p1 p2 => cat | func p1 | func p2
    filter p1 p2 ... pN => cat | func p1 | func p2 | ... | func pN

    where "func" is working as filter and accepts exactly one parameter.

    (Because of reservations I have with 'eval' and quoting I'd like to
    avoid that 'eval' indirection if possible.)

    I think it's [in principle] not possible [without 'eval'] in shell
    (POSIX, Ksh, Bash) but I'm interested to hear opinions...

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Janis Papanagnou on Wed May 7 02:25:15 2025
    On 2025-05-07, Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
    I'm pondering about creating a functional processing pipe, depending
    on program parameters, and whether that's possible to achieve without
    using 'eval'.

    Say, the program is called "filter" and may accept 0..N parameters and depending on the set of parameters the respective pipe functionality
    shall be defined like

    filter => cat
    filter p1 => cat | func p1
    filter p1 p2 => cat | func p1 | func p2
    filter p1 p2 ... pN => cat | func p1 | func p2 | ... | func pN

    where "func" is working as filter and accepts exactly one parameter.

    The problem is that the number of pipes on the right hand side
    depends on the number of arguments.

    The number of pipes in a command pipe is a property of syntax;
    it is something that needs eval.

    If you're interested in being able to make this kind of code
    transformation, perhaps you should start a project to add macros to a
    shell. (An educated guess informs me that you'd likely choose Korn).

    Macros avoid extra eval by taking advantage of the result of the
    substitution being "naturally thrown into the path of the evaluator",
    just like any other code that is not expanded by a macro.


    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Kaz Kylheku on Wed May 7 10:16:39 2025
    On 07.05.2025 04:25, Kaz Kylheku wrote:
    On 2025-05-07, Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
    I'm pondering about creating a functional processing pipe, depending
    on program parameters, and whether that's possible to achieve without
    using 'eval'.

    Say, the program is called "filter" and may accept 0..N parameters and
    depending on the set of parameters the respective pipe functionality
    shall be defined like

    filter => cat
    filter p1 => cat | func p1
    filter p1 p2 => cat | func p1 | func p2
    filter p1 p2 ... pN => cat | func p1 | func p2 | ... | func pN

    where "func" is working as filter and accepts exactly one parameter.

    The problem is that the number of pipes on the right hand side
    depends on the number of arguments.

    The number of pipes in a command pipe is a property of syntax;

    Yes, this is the key observation!

    it is something that needs eval.

    If you're interested in being able to make this kind of code
    transformation, perhaps you should start a project to add macros to a
    shell. (An educated guess informs me that you'd likely choose Korn).

    Yes, Ksh is my standard shell.

    But if there'd be (beyond 'eval') some sort of "meta-feature" in Bash
    (or in other shell) I'd also be interested. Something safer and less troublesome (quoting!) than 'eval'.


    Macros avoid extra eval by taking advantage of the result of the
    substitution being "naturally thrown into the path of the evaluator",
    just like any other code that is not expanded by a macro.

    Hmm.., yes, macros is a possible way to go. (Not sure I'd like to
    take that path.) I'll think about that.

    Thanks for the confirmation and for the suggestion!

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Lars Poulsen@21:1/5 to Janis Papanagnou on Wed May 7 12:58:05 2025
    On 2025-05-07, Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
    I'm pondering about creating a functional processing pipe, depending
    on program parameters, and whether that's possible to achieve without
    using 'eval'.

    Say, the program is called "filter" and may accept 0..N parameters and depending on the set of parameters the respective pipe functionality
    shall be defined like

    filter => cat
    filter p1 => cat | func p1
    filter p1 p2 => cat | func p1 | func p2
    filter p1 p2 ... pN => cat | func p1 | func p2 | ... | func pN

    where "func" is working as filter and accepts exactly one parameter.

    (Because of reservations I have with 'eval' and quoting I'd like to
    avoid that 'eval' indirection if possible.)

    For a limited number of arguments, you could do it with a switch,
    enumerating the variations. I can see the utility of such a feature.

    It seems that you could do this with a small wrapper program (in your
    favorite progframming language) activating the shell once the pipeline
    has been constructed.

    I would like to have this king of feature wrapped around grep in order
    to do compounded keyword searches, but it's not a high priority.

    Lars

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Lars Poulsen on Wed May 7 17:07:14 2025
    On 07.05.2025 14:58, Lars Poulsen wrote:
    On 2025-05-07, Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
    I'm pondering about creating a functional processing pipe, depending
    on program parameters, and whether that's possible to achieve without
    using 'eval'.

    Say, the program is called "filter" and may accept 0..N parameters and
    depending on the set of parameters the respective pipe functionality
    shall be defined like

    filter => cat
    filter p1 => cat | func p1
    filter p1 p2 => cat | func p1 | func p2
    filter p1 p2 ... pN => cat | func p1 | func p2 | ... | func pN

    where "func" is working as filter and accepts exactly one parameter.

    (Because of reservations I have with 'eval' and quoting I'd like to
    avoid that 'eval' indirection if possible.)

    For a limited number of arguments, you could do it with a switch,
    enumerating the variations. I can see the utility of such a feature.

    Well, for the application case I have in mind that would indeed be
    possible; I expect not more than a handful of arguments in one call.

    Only such hard coded solutions repel me; triggers some aesthetics
    nerves badly.


    It seems that you could do this with a small wrapper program (in your favorite progframming language) activating the shell once the pipeline
    has been constructed.

    Well, yes. In an abstract thought that was the direction I was
    thinking of, but I couldn't really wrap my head around it with
    the tools I'm using. (I'd think with Lisp or other functional
    languages you may get that out of the box, but I'm with Shell
    and Awk at the moment.)


    I would like to have this king of feature wrapped around grep in order
    to do compounded keyword searches, but it's not a high priority.

    I recall I've done such with 'grep', simply transforming the
    shell arguments to a 'grep' argument. It was simple, like

    x=$*
    grep -E '('"${x// /|}"')'


    (BTW, strangely, using "${*// /|}" straightly (without 'x')
    doesn't seem to work for that.)

    Janis


    Lars


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Janis Papanagnou on Wed May 7 17:19:48 2025
    On 07.05.2025 17:07, Janis Papanagnou wrote:
    On 07.05.2025 14:58, Lars Poulsen wrote:

    I would like to have this king of feature wrapped around grep in order
    to do compounded keyword searches, but it's not a high priority.

    I recall I've done such with 'grep', simply transforming the
    shell arguments to a 'grep' argument. It was simple, like

    x=$*
    grep -E '('"${x// /|}"')'

    grep -E "${x// /|}"

    ...this should suffice (the parenthesis are not necessary).

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ben Bacarisse@21:1/5 to Janis Papanagnou on Wed May 7 17:57:46 2025
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:

    I'm pondering about creating a functional processing pipe, depending
    on program parameters, and whether that's possible to achieve without
    using 'eval'.

    Say, the program is called "filter" and may accept 0..N parameters and depending on the set of parameters the respective pipe functionality
    shall be defined like

    filter => cat
    filter p1 => cat | func p1
    filter p1 p2 => cat | func p1 | func p2
    filter p1 p2 ... pN => cat | func p1 | func p2 | ... | func pN

    where "func" is working as filter and accepts exactly one parameter.

    You don't really need the initial cat except when there are no
    arguments. Using this fact, and provided you don't mind an extra cat
    command at the end of the pipe, does this do what you want:

    #!/bin/bash

    function recurse
    {
    if [[ $# -ge 1 ]]
    then grep "$1" | (shift; recurse "$@")
    else cat
    fi
    }

    recurse "$@"

    (I'm using grep and the filer here because it permits simple testing.)

    I think one could remove the final cat command, but I'm in hurry to
    catch the shops!

    --
    Ben.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Ben Bacarisse on Wed May 7 21:11:30 2025
    On 07.05.2025 18:57, Ben Bacarisse wrote:
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:

    I'm pondering about creating a functional processing pipe, depending
    on program parameters, and whether that's possible to achieve without
    using 'eval'.

    Say, the program is called "filter" and may accept 0..N parameters and
    depending on the set of parameters the respective pipe functionality
    shall be defined like

    filter => cat
    filter p1 => cat | func p1
    filter p1 p2 => cat | func p1 | func p2
    filter p1 p2 ... pN => cat | func p1 | func p2 | ... | func pN

    where "func" is working as filter and accepts exactly one parameter.

    You don't really need the initial cat except when there are no
    arguments.

    Yes. As far as I see we need some terminator at one end of the pipe
    if we have that in some construction context ('eval'-.string or pipe).
    I used it at the front of the pipeline because it allows for a simple
    logic; my 'eval'-based logic (that I wanted to avoid) looks like this

    pipe="cat"
    for p in "$@"
    do
    pipe="${pipe} | func '${p}'"
    done
    eval "${pipe}"

    and it reflects the four samples we see above (with 'cat' in front).

    Using this fact, and provided you don't mind an extra cat
    command at the end of the pipe,

    I don't mind an extra 'cat'. Whether its at the front or rear is not
    too different (as far as I see).

    does this do what you want:

    #!/bin/bash

    function recurse
    {
    if [[ $# -ge 1 ]]
    then grep "$1" | (shift; recurse "$@")
    else cat
    fi
    }

    recurse "$@"

    This is very nice! - It definitely works for me and does what I want.
    Thanks!


    (I'm using grep and the filer here because it permits simple testing.)

    Did you mean "as the filter"? (Otherwise please explain the "filer".)


    I think one could remove the final cat command, but I'm in hurry to
    catch the shops!

    I certainly need a "transparent" (idempotent) function if there are no arguments provided, so a 'cat' is what I need in that case. (An empty
    output would definitely be wrong for me.) And the unnecessary 'cat' at
    the pipe end(s) is an acceptable unimportant degradation (for me). But
    if you have an idea how to remove it... :-)

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Christian Weisgerber@21:1/5 to Janis Papanagnou on Wed May 7 21:35:16 2025
    On 2025-05-07, Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:

    function recurse
    {
    if [[ $# -ge 1 ]]
    then grep "$1" | (shift; recurse "$@")
    else cat
    fi
    }

    I certainly need a "transparent" (idempotent) function if there are no arguments provided, so a 'cat' is what I need in that case. (An empty
    output would definitely be wrong for me.) And the unnecessary 'cat' at
    the pipe end(s) is an acceptable unimportant degradation (for me). But
    if you have an idea how to remove it... :-)

    recurse()
    {
    case $# in
    0) cat ;;
    1) grep "$1" ;;
    *) grep "$1" | (shift; recurse "$@") ;;
    esac
    }

    --
    Christian "naddy" Weisgerber naddy@mips.inka.de

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Christian Weisgerber on Thu May 8 00:55:31 2025
    On 07.05.2025 23:35, Christian Weisgerber wrote:
    On 2025-05-07, Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:

    function recurse
    {
    if [[ $# -ge 1 ]]
    then grep "$1" | (shift; recurse "$@")
    else cat
    fi
    }

    I certainly need a "transparent" (idempotent) function if there are no
    arguments provided, so a 'cat' is what I need in that case. (An empty
    output would definitely be wrong for me.) And the unnecessary 'cat' at
    the pipe end(s) is an acceptable unimportant degradation (for me). But
    if you have an idea how to remove it... :-)

    recurse()
    {
    case $# in
    0) cat ;;
    1) grep "$1" ;;
    *) grep "$1" | (shift; recurse "$@") ;;
    esac
    }


    Hah, simple and straightforward, that's great! 8-)

    Thanks :-)

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)