zsh-users
 help / color / mirror / code / Atom feed
* virtual files?
@ 2016-04-20  1:00 Emanuel Berg
  2016-04-20  1:27 ` Nikolay Aleksandrovich Pavlov (ZyX)
  2016-04-20  3:32 ` Benjamin R. Haskell
  0 siblings, 2 replies; 15+ messages in thread
From: Emanuel Berg @ 2016-04-20  1:00 UTC (permalink / raw)
  To: zsh-users

Here is a program I just wrote.

Feel free to comment on any part.

However my specific question is, instead of using the
"result_file" stuff, is there support for
I suppose "virtual files" or basically a data structure
that can be used transparently as a file, or with but
small adjustments?

TIA.

#! /bin/zsh

# This file: http://user.it.uu.se/~embe8573/conf/.zsh/money

# zsh CLI to Internet inflation calculator.
#
# Try, for example, three K2 expeditions:
#
#     $ inflation 9000 1938; inflation 30958.33 1953; inflation 108000 1954
#
# which yields:
#
#     $151,999.15
#     $276,111.20
#     $956,069.00

inflation () {
    local usd=${1:-10}

    # year
    local then=${2:-1950}
    local now=`date +"%Y"`

    local result_file=result

    local link="http://data.bls.gov/cgi-bin/cpicalc.pl?cost1=$usd&year1=$then&year2=$now"
    wget -q $link -O $result_file

    echo -n \$
    grep \"answer\" $result_file | cut -d \$ -f 2 | cut -d \< -f 1

    rm $result_file
}

-- 
underground experts united .... http://user.it.uu.se/~embe8573
Emacs Gnus Blogomatic ......... http://user.it.uu.se/~embe8573/blogomatic
                   - so far: 25 Blogomatic articles -                   


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: virtual files?
  2016-04-20  1:00 virtual files? Emanuel Berg
@ 2016-04-20  1:27 ` Nikolay Aleksandrovich Pavlov (ZyX)
  2016-04-20  2:12   ` Emanuel Berg
  2016-04-20  3:32 ` Benjamin R. Haskell
  1 sibling, 1 reply; 15+ messages in thread
From: Nikolay Aleksandrovich Pavlov (ZyX) @ 2016-04-20  1:27 UTC (permalink / raw)
  To: Emanuel Berg, zsh-users

20.04.2016, 04:19, "Emanuel Berg" <embe8573@student.uu.se>:
> Here is a program I just wrote.
>
> Feel free to comment on any part.
>
> However my specific question is, instead of using the
> "result_file" stuff, is there support for
> I suppose "virtual files" or basically a data structure
> that can be used transparently as a file, or with but
> small adjustments?
>
> TIA.
>
> #! /bin/zsh
>
> # This file: http://user.it.uu.se/~embe8573/conf/.zsh/money
>
> # zsh CLI to Internet inflation calculator.
> #
> # Try, for example, three K2 expeditions:
> #
> # $ inflation 9000 1938; inflation 30958.33 1953; inflation 108000 1954
> #
> # which yields:
> #
> # $151,999.15
> # $276,111.20
> # $956,069.00
>
> inflation () {
>     local usd=${1:-10}
>
>     # year
>     local then=${2:-1950}
>     local now=`date +"%Y"`
>
>     local result_file=result
>
>     local link="http://data.bls.gov/cgi-bin/cpicalc.pl?cost1=$usd&year1=$then&year2=$now"
>     wget -q $link -O $result_file
>
>     echo -n \$
>     grep \"answer\" $result_file | cut -d \$ -f 2 | cut -d \< -f 1
>
>     rm $result_file
> }

In some cases you may use `>(process)` to create file descriptor that will be used like a named pipe and may replace real files in some cases (it does not support seek(), also some processes have a habit of closing all file descriptors except stdin/stdout/stderr). But it is launched in subshell which limits the usefullness further (i.e. you cannot directly save result in a variable).

Specifically this function does not need >() or any file at all:

    …
    echo -n \$
    wget -q $link -O- | grep answer | cut -d \$ -f2 | cut -d \< -f1
    …

>
> --
> underground experts united .... http://user.it.uu.se/~embe8573
> Emacs Gnus Blogomatic ......... http://user.it.uu.se/~embe8573/blogomatic
>                    - so far: 25 Blogomatic articles -


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: virtual files?
  2016-04-20  1:27 ` Nikolay Aleksandrovich Pavlov (ZyX)
@ 2016-04-20  2:12   ` Emanuel Berg
  2016-04-20  2:31     ` Nikolay Aleksandrovich Pavlov (ZyX)
  2016-04-20  4:03     ` Bart Schaefer
  0 siblings, 2 replies; 15+ messages in thread
From: Emanuel Berg @ 2016-04-20  2:12 UTC (permalink / raw)
  To: zsh-users

"Nikolay Aleksandrovich Pavlov (ZyX)"
<kp-pav@yandex.ru> writes:

> In some cases you may use `>(process)` to create
> file descriptor that will be used like a named pipe
> and may replace real files in some cases (it does
> not support seek(), also some processes have a habit
> of closing all file descriptors except
> stdin/stdout/stderr). But it is launched in subshell
> which limits the usefullness further (i.e.
> you cannot directly save result in a variable).

OK! That doesn't seem like any good samochuvstvie...

> Specifically this function does not need >() or any
> file at all:
>
>     ... echo -n \$ wget -q $link -O- | grep answer | cut
> -d \$ -f2 | cut -d \< -f1 ...

But you still need the escaped quotes around "answer"
otherwise it won't work due to the HTML data :)

Now, it is true you don't *need* files here or in
other situations like this. But it is a very good
thing to have, to be able to name something something,
and then stash the result there for future use.
A variable or data structure, in essence.

Obviously creating a normal file just to remove it
last thing doesn't score you any hacker points...

So I think this is a good idea for you to contemplate
incorporating in zsh!

-- 
underground experts united .... http://user.it.uu.se/~embe8573
Emacs Gnus Blogomatic ......... http://user.it.uu.se/~embe8573/blogomatic
                   - so far: 25 Blogomatic articles -                   


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: virtual files?
  2016-04-20  2:12   ` Emanuel Berg
@ 2016-04-20  2:31     ` Nikolay Aleksandrovich Pavlov (ZyX)
  2016-04-20  4:03     ` Bart Schaefer
  1 sibling, 0 replies; 15+ messages in thread
From: Nikolay Aleksandrovich Pavlov (ZyX) @ 2016-04-20  2:31 UTC (permalink / raw)
  To: Emanuel Berg, zsh-users

20.04.2016, 05:13, "Emanuel Berg" <embe8573@student.uu.se>:
> "Nikolay Aleksandrovich Pavlov (ZyX)"
> <kp-pav@yandex.ru> writes:
>
>>  In some cases you may use `>(process)` to create
>>  file descriptor that will be used like a named pipe
>>  and may replace real files in some cases (it does
>>  not support seek(), also some processes have a habit
>>  of closing all file descriptors except
>>  stdin/stdout/stderr). But it is launched in subshell
>>  which limits the usefullness further (i.e.
>>  you cannot directly save result in a variable).
>
> OK! That doesn't seem like any good samochuvstvie...
>
>>  Specifically this function does not need >() or any
>>  file at all:
>>
>>      ... echo -n \$ wget -q $link -O- | grep answer | cut
>>  -d \$ -f2 | cut -d \< -f1 ...
>
> But you still need the escaped quotes around "answer"
> otherwise it won't work due to the HTML data :)
>
> Now, it is true you don't *need* files here or in
> other situations like this. But it is a very good
> thing to have, to be able to name something something,
> and then stash the result there for future use.
> A variable or data structure, in essence.

For `wget -Ofoo` there may not be any variable/data structure. At all, file `foo` in this example is created by *wget*, zsh *cannot* intervent here: all it knows is that `wget` received argument `-Ofoo` which is a plain string like any other argument, it does not know what `foo` is (completion system is a separate thing and it can only make *guesses*, not know for sure). If you really need this you can create something like temporary tmpfs via FUSE which will be automatically unmounted when scripts exits, and this does not require any special support on zsh side.

As the other alternative one may create something like `=()` to work like “create temporary file, substitute its name here, after process finishes save file contents in the variable and remove it”. Basically a syntactic sugar for what you currently are doing, should be relatively easy (I did not look at relevant parts of the code though). Most of time this is not really needed: you may simply use stdout or stderr. Least of time… well, this is a *shell* language, complex applications were never its target. I believe this is why better integration with subprocesses is not implemented yet, though I sometimes see problems which would be solved much easier if e.g. when opening subshell zsh created a file descriptor through which updates to variables would be directed (i.e. something like a command socket, but through a pipe).

>
> Obviously creating a normal file just to remove it
> last thing doesn't score you any hacker points...
>
> So I think this is a good idea for you to contemplate
> incorporating in zsh!
>
> --
> underground experts united .... http://user.it.uu.se/~embe8573
> Emacs Gnus Blogomatic ......... http://user.it.uu.se/~embe8573/blogomatic
>                    - so far: 25 Blogomatic articles -


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: virtual files?
  2016-04-20  1:00 virtual files? Emanuel Berg
  2016-04-20  1:27 ` Nikolay Aleksandrovich Pavlov (ZyX)
@ 2016-04-20  3:32 ` Benjamin R. Haskell
  2016-04-20 20:34   ` Bart Schaefer
  2016-04-21  4:12   ` Emanuel Berg
  1 sibling, 2 replies; 15+ messages in thread
From: Benjamin R. Haskell @ 2016-04-20  3:32 UTC (permalink / raw)
  To: Zsh-Users List

[-- Attachment #1: Type: text/plain, Size: 3760 bytes --]

On Tue, Apr 19, 2016 at 9:00 PM, Emanuel Berg <embe8573@student.uu.se>
wrote:

> Here is a program I just wrote.
>
> Feel free to comment on any part.
>
> However my specific question is, instead of using the
> "result_file" stuff, is there support for
> I suppose "virtual files" or basically a data structure
> that can be used transparently as a file, or with but
> small adjustments?
>
> TIA.
>
> #! /bin/zsh
>
> # This file: http://user.it.uu.se/~embe8573/conf/.zsh/money
>
> # zsh CLI to Internet inflation calculator.
> #
> # Try, for example, three K2 expeditions:
> #
> #     $ inflation 9000 1938; inflation 30958.33 1953; inflation 108000 1954
> #
> # which yields:
> #
> #     $151,999.15
> #     $276,111.20
> #     $956,069.00
>
> inflation () {
>     local usd=${1:-10}
>
>     # year
>     local then=${2:-1950}
>     local now=`date +"%Y"`
>
>     local result_file=result
>
>     local link="
> http://data.bls.gov/cgi-bin/cpicalc.pl?cost1=$usd&year1=$then&year2=$now"
>     wget -q $link -O $result_file
>
>     echo -n \$
>     grep \"answer\" $result_file | cut -d \$ -f 2 | cut -d \< -f 1
>
>     rm $result_file
> }
>

Using the `=()` substitution ZyX mentions:

inflation () {
  local usd=${1:-10}
  # year
  local then=${2:-1950}
  local now=`date +"%Y"`
  local link="
http://data.bls.gov/cgi-bin/cpicalc.pl?cost1=$usd&year1=$then&year2=$now"
  () {
    local tmp=$1
    wget -q $link -O $tmp
    echo -n \$
    grep \"answer\" $tmp | cut -d \$ -f 2 | cut -d \< -f 1
  } =(:)
}

The '() { ... }' construct is an anonymous function, just for controlling
the scope of the temporary file, and for passing it in as a positional
parameter.  It has the disadvantage that it won't remove the tmp file if
something goes wrong.

Personally, for portable scripts (not usually functions), I tend to use
`mktemp` + `trap cleanup INT QUIT EXIT` (where `cleanup` is a per-script
function for removing whatever temp files I create in that script).

E.g., in this case, since it's a single tmp file, you may as well inline
the trap body:

inflation () {
  local usd=${1:-10}
  # year
  local then=${2:-1950}
  local now=`date +"%Y"`
  local link="
http://data.bls.gov/cgi-bin/cpicalc.pl?cost1=$usd&year1=$then&year2=$now"
  # not sure which of these are default:
  setopt local_options no_posix_traps local_traps err_return
  # -t means "use $TMPDIR" for some `mktemp`s, "next arg is template" for
others
  local tmp=$(mktemp -t inflation.data.XXXXXXXX)
  # remove the tmp file on exit, if it was set up properly
  trap '[[ -z $tmp ]] || rm $tmp' INT QUIT EXIT
  wget -q $link -O $tmp
  echo -n \$
  grep \"answer\" $tmp | cut -d \$ -f 2 | cut -d \< -f 1
}

Another possibility is the use of `coproc` (which I only see mentioned
twice in `zshall(1)`), so I feel like it doesn't get used often, and only
works in this case because `wget` is capable of using stdout: (but is
nonetheless potentially interesting):

inflation () {
  local usd=${1:-10}
  # year
  local then=${2:-1950}
  local now=`date +"%Y"`
  local link="
http://data.bls.gov/cgi-bin/cpicalc.pl?cost1=$usd&year1=$then&year2=$now"
  coproc wget -q $link -O -
  echo -n \$
  grep \"answer\" <&p | cut -d \$ -f 2 | cut -d \< -f 1
}

The `coproc` preceding the `wget` starts a background process, then `>&p` =
write to the process (not used here), `<&p` = read from the process (used
for the input to `grep`).

Also, I prefer `curl` over `wget`, and if you're curious, here's how I
might write the entire function:

inflation() {
  curl -s -d cost1=${1:-10} -d year1=${2:-1950} -d year2=$(date +%Y) \
    http://data.bls.gov/cgi-bin/cpicalc.pl |
  awk '/"answer"/' |
  tr -d -c '$0-9.,\n'
}

(Though the create-a-tempfile problem is certainly interesting in its own
right.)

-- 
Best,
Ben

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: virtual files?
  2016-04-20  2:12   ` Emanuel Berg
  2016-04-20  2:31     ` Nikolay Aleksandrovich Pavlov (ZyX)
@ 2016-04-20  4:03     ` Bart Schaefer
  2016-04-20  6:06       ` Emanuel Berg
  2016-04-21 22:14       ` Emanuel Berg
  1 sibling, 2 replies; 15+ messages in thread
From: Bart Schaefer @ 2016-04-20  4:03 UTC (permalink / raw)
  To: zsh-users

On Apr 20,  2:12am, Emanuel Berg wrote:
}
} Obviously creating a normal file just to remove it
} last thing doesn't score you any hacker points...
} 
} So I think this is a good idea for you to contemplate
} incorporating in zsh!

The problem is that implementing something like this in the shell is
fairly useless, because none of the other tools that the shell might
invoke would know what to do with it.  This is why you need something
operating-system-level like FUSE (as Nikolay mentioned), which can
make the virtual object "look like" an ordinary file or descriptor to
anything using the ordinary libraries/interfaces.

Also as Nikolay sort of mentioned in passing, you can replace

    local result_file=result
    wget -q $link -O $result_file
    grep \"answer\" $result_file | ...
    rm $result_file

with

    grep \"answer\" =(wget -q $link -O -) | ...

and zsh will take care of creating/removing the temp file for you.
You can further do

    exec {result_fd}< =(wget -q $link -O -)

and now $result_fd is a descriptor holding open an unlinked file.  If
you load the zsh/system module, you can

    grep \"answer\" <&$result_fd | ...
    sysseek -u $result_id 0

If all you're wanting is to capture output in a variable, you can use
the "read" command (or use "sysread" from zsh/system).  Zsh arranges
for "read" at the tail of a pipe to execute in the current shell
(unlike most other shells that put the pipe tail in a subshell) so

    wget -q $link -O - | read -d '' result

loads the output of wget directly into $result.

There are other things you can do e.g. with the zsh/mapfile module or
the zsh/db/gdbm module (I recommend a very recent zsh if you plan to
do anything serious with the latter), but I've rambled enough.


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: virtual files?
  2016-04-20  4:03     ` Bart Schaefer
@ 2016-04-20  6:06       ` Emanuel Berg
  2016-04-21 22:14       ` Emanuel Berg
  1 sibling, 0 replies; 15+ messages in thread
From: Emanuel Berg @ 2016-04-20  6:06 UTC (permalink / raw)
  To: zsh-users

Bart Schaefer <schaefer@brasslantern.com> writes:

> ... but I've rambled enough.

Ha ha, good rambling from all three of you!

God willing I'll be back with a few more questions
after I make a closer reading of this material.

-- 
underground experts united .... http://user.it.uu.se/~embe8573
Emacs Gnus Blogomatic ......... http://user.it.uu.se/~embe8573/blogomatic
                   - so far: 26 Blogomatic articles -                   


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: virtual files?
  2016-04-20  3:32 ` Benjamin R. Haskell
@ 2016-04-20 20:34   ` Bart Schaefer
  2016-04-22  5:26     ` Benjamin R. Haskell
  2016-04-21  4:12   ` Emanuel Berg
  1 sibling, 1 reply; 15+ messages in thread
From: Bart Schaefer @ 2016-04-20 20:34 UTC (permalink / raw)
  To: Zsh-Users List

On Apr 19, 11:32pm, Benjamin R. Haskell wrote:
}
} Using the `=()` substitution ZyX mentions:
} 
}   () {
}     local tmp=$1
}     wget -q $link -O $tmp
}     echo -n \$
}     grep \"answer\" $tmp | cut -d \$ -f 2 | cut -d \< -f 1
}   } =(:)
} 
} The '() { ... }' construct is an anonymous function, just for controlling
} the scope of the temporary file, and for passing it in as a positional
} parameter.  It has the disadvantage that it won't remove the tmp file if
} something goes wrong.

In fact the point of using =(:) is that it WILL remove the tmp file if
something goes wrong (unless it's something completely catastrophic like
the shell itself crashing, but in that case an explicit "rm" wouldn't
work either).

Instead of exit traps, you can use "always" blocks:

  () {
    local tmp=$1;
    {
      : do stuff with $tmp
      exit
    } always {
      rm $tmp
    }
  } =(:)


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: virtual files?
  2016-04-20  3:32 ` Benjamin R. Haskell
  2016-04-20 20:34   ` Bart Schaefer
@ 2016-04-21  4:12   ` Emanuel Berg
  2016-04-21  6:58     ` Bart Schaefer
  2016-04-22  5:55     ` Benjamin R. Haskell
  1 sibling, 2 replies; 15+ messages in thread
From: Emanuel Berg @ 2016-04-21  4:12 UTC (permalink / raw)
  To: zsh-users

"Benjamin R. Haskell" <zsh@benizi.com> writes:

> Using the `=()` substitution ZyX mentions:
>
> inflation () {
>   local usd=${1:-10}
>   # year
>   local then=${2:-1950}
>   local now=`date +"%Y"`
>   local link="
> http://data.bls.gov/cgi-bin/cpicalc.pl?cost1=$usd&year1=$then&year2=$now"
>   () {
>     local tmp=$1
>     wget -q $link -O $tmp
>     echo -n \$
>     grep \"answer\" $tmp | cut -d \$ -f 2 | cut -d \< -f 1
>   } =(:)
> }

Great!

If was something like that I had in mind. Tho the
mental image was more like the Lisp syntax for doing
scopes, e.g. `let' and `with-selected-frame' in:

    (defun new-frame-show-grep ()
      (let ((new-frame (make-frame-command)))
        (setq *grep-frame* new-frame)
        (with-selected-frame new-frame
          (switch-to-buffer "*grep*") )))

Actually the zsh anonymous function syntax doesn't
remind me of anything I've seen, save for perhaps some
stuff in zsh itself. The parameter list and body
without a name make sense, but what comes after the
closing curly bracket looks like a ghost, wearing
a tie...

What is the colon in =(:) - an "anonymous function
qualifier"?

Only remark is, if you do all this trouble to get
clean code, and then name the local "tmp", it is
almost comical. But I get it, you did that for me (all
readers), not the code per se...

> Also, I prefer `curl` over `wget`, and if you're
> curious, here's how I might write the entire
> function:

I have used them both and never reflected on which was
superior, but taking a look at your code:

> inflation() {
>   curl -s -d cost1=${1:-10} -d year1=${2:-1950} -d year2=$(date +%Y) \
>     http://data.bls.gov/cgi-bin/cpicalc.pl |
>   awk '/"answer"/' |
>   tr -d -c '$0-9.,\n'
> }

I agree that using the --data's to set up the
CGI-to-be-Perl-input arguments is less hackish than
putting together the URL manually (fine, just once,
but anyway is much less clear). Ironic thing is, doing
it manually might actually be faster since you can
then just copy-paste and modify the URL. So anyway
I changed to curl, only I somewhat didn't use your
compact style.

awk instead of grep in this context should be strange
to many who are more familiar with grep, but grep has
the problem that many like to put colorization to it
which can screw up parsing. If the configuration
is in an environmental, I suppose not even giving the
full path to the binary to bypass an alias would get
them away. One can supply a specification, of course,
telling grep not to use colors, but rather than doing
that, I switched to awk as you suggested.

I also changed the two cut:s for tr, and date +%Y from
the `one` syntax form into $(another).
Those I consider even more minor improvements, however
they are still better so I changed them as well. If it
is meaningless to do, I might as well do it!

So here is the latest version:

inflation () {
    local url=http://data.bls.gov/cgi-bin/cpicalc.pl
    curl -s                   \
         -d cost1=${1:-10}    \
         -d year1=${2:-1950}  \
         -d year2=$(date +%Y) $url |
        awk '/"answer"/'           |
        tr -d -c '$0-9.,\n'
}

One interesting thing is tho I changed three programs
out of three used, I don't think this function is
anything "remote" to the one I originally wrote.
A small homage to the diversity of the Linux/Unix
tools, I suppose. But come to think of it there are
many players in the NHL that score some ~15 goals
every season, but that doesn't mean they cannot also
be completely different players, physical aspects as
well as those of skill and style...

> (Though the create-a-tempfile problem is certainly
> interesting in its own right.)

Yes.

It cannot be like this for too many steps, is my take:

    a | b | ... | n

But this looks like some TI-82 stuff I kid would do

    let f=file_path
    # do things to f
    rm $f

As for now, what I'll do is to keep it short, stupid!
(KISS - Thatcher quote, I think) and so be able to put
together parsings, and when that doesn't work as in
longer pieces of software, I'll consider getting som
order by use of the anonymous software.

http://user.it.uu.se/~embe8573/conf/.zsh/money

-- 
underground experts united .... http://user.it.uu.se/~embe8573
Emacs Gnus Blogomatic ......... http://user.it.uu.se/~embe8573/blogomatic
                   - so far: 26 Blogomatic articles -                   


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: virtual files?
  2016-04-21  4:12   ` Emanuel Berg
@ 2016-04-21  6:58     ` Bart Schaefer
  2016-04-21  8:05       ` Emanuel Berg
  2016-04-22  5:55     ` Benjamin R. Haskell
  1 sibling, 1 reply; 15+ messages in thread
From: Bart Schaefer @ 2016-04-21  6:58 UTC (permalink / raw)
  To: zsh-users

On Apr 21,  4:12am, Emanuel Berg wrote:
} 
} What is the colon in =(:) - an "anonymous function
} qualifier"?

The syntax =(command) runs command and captures its output in a temp
file, then substitutes the name of the temp file; the file itself is
removed as soon as the current command finishes.  So

    echo =(echo foo)

will print something like /tmp/zshhKNk2F and

    cat =(echo foo)

will print foo.

Thus

    () { cat $1 } =(echo foo)

also prints foo.  The ":" command is just a quick built-in no-op that
produces no output, so that the temporary file created by =(:) will
be empty.


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: virtual files?
  2016-04-21  6:58     ` Bart Schaefer
@ 2016-04-21  8:05       ` Emanuel Berg
  0 siblings, 0 replies; 15+ messages in thread
From: Emanuel Berg @ 2016-04-21  8:05 UTC (permalink / raw)
  To: zsh-users

Bart Schaefer <schaefer@brasslantern.com> writes:

> Thus
>
>     () { cat $1 } =(echo foo)
>
> also prints foo. The ":" command is just a quick
> built-in no-op that produces no output, so that the
> temporary file created by =(:) will be empty.

Got it!

This also means if you want to have several local
files (names to temporary files) in the same limited
scope you have to stack several =(:) as well!

-- 
underground experts united .... http://user.it.uu.se/~embe8573
Emacs Gnus Blogomatic ......... http://user.it.uu.se/~embe8573/blogomatic
                   - so far: 26 Blogomatic articles -                   


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: virtual files?
  2016-04-20  4:03     ` Bart Schaefer
  2016-04-20  6:06       ` Emanuel Berg
@ 2016-04-21 22:14       ` Emanuel Berg
  2016-04-22  1:08         ` Bart Schaefer
  1 sibling, 1 reply; 15+ messages in thread
From: Emanuel Berg @ 2016-04-21 22:14 UTC (permalink / raw)
  To: zsh-users

Bart Schaefer <schaefer@brasslantern.com> writes:

> The problem is that implementing something like this
> in the shell is fairly useless, because none of the
> other tools that the shell might invoke would know
> what to do with it. This is why you need something
> operating-system-level like FUSE (as Nikolay
> mentioned), which can make the virtual object "look
> like" an ordinary file or descriptor to anything
> using the ordinary libraries/interfaces.

That sure is the international superstar hitman
approach but it appears to be overkill (ha) not only
for this example but also for whatever else I've done
and am doing at the zsh and CLI tool level.

Also there is some virtue in having the software which
you use the most at some level of isolation from the
OS (or the OS below I should say). It is a good
feeling, and an efficient method, to just be able to
bring over your Emacs and zsh gear from one system to
another and virtually have the same user experience,
all but instantly. And I have actually succeeded doing
that! Sometimes...

> If all you're wanting is to capture output in
> a variable, you can use the "read" command (or use
> "sysread" from zsh/system). Zsh arranges for "read"
> at the tail of a pipe to execute in the current
> shell (unlike most other shells that put the pipe
> tail in a subshell) so
>
>     wget -q $link -O - | read -d '' result
>
> loads the output of wget directly into $result.

... :O

I can't believe I missed this the first time I read
this message! But if I hadn't, I wouldn't have learned
about the () { } =() thing so I suppose it was my
ancestors having my back, as always.

"If all you're wanting"...? :)

But yes, this is exactly what I want!

    read-test () {
        local url=http://data.bls.gov/cgi-bin/cpicalc.pl
        local result
        wget -q $url -O - | read -d '' result
        echo $result
    }

(I suppose the "delimiter" is EOF if set to nothing.)

Now I'll dig deep into all my shell programming and
see if I can prune some unnecessary creation and
removal of filesystem files. Delightful!

-- 
underground experts united .... http://user.it.uu.se/~embe8573
Emacs Gnus Blogomatic ......... http://user.it.uu.se/~embe8573/blogomatic
                   - so far: 26 Blogomatic articles -                   


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: virtual files?
  2016-04-21 22:14       ` Emanuel Berg
@ 2016-04-22  1:08         ` Bart Schaefer
  0 siblings, 0 replies; 15+ messages in thread
From: Bart Schaefer @ 2016-04-22  1:08 UTC (permalink / raw)
  To: zsh-users

On Apr 22, 12:14am, Emanuel Berg wrote:
}
}     read-test () {
}         local url=http://data.bls.gov/cgi-bin/cpicalc.pl
}         local result
}         wget -q $url -O - | read -d '' result
}         echo $result
}     }

You probably want
  print -r -- $result
to avoid any leading hyphens or other misc. sequences in $result from
being interpreted by echo.

} (I suppose the "delimiter" is EOF if set to nothing.)

Effectively yes.


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: virtual files?
  2016-04-20 20:34   ` Bart Schaefer
@ 2016-04-22  5:26     ` Benjamin R. Haskell
  0 siblings, 0 replies; 15+ messages in thread
From: Benjamin R. Haskell @ 2016-04-22  5:26 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh-Users List

[-- Attachment #1: Type: text/plain, Size: 1547 bytes --]

On Wed, Apr 20, 2016 at 4:34 PM, Bart Schaefer <schaefer@brasslantern.com>
wrote:

> On Apr 19, 11:32pm, Benjamin R. Haskell wrote:
> }
> } Using the `=()` substitution ZyX mentions:
> }
> }   () {
> }     local tmp=$1
> }     wget -q $link -O $tmp
> }     echo -n \$
> }     grep \"answer\" $tmp | cut -d \$ -f 2 | cut -d \< -f 1
> }   } =(:)
> }
> } The '() { ... }' construct is an anonymous function, just for controlling
> } the scope of the temporary file, and for passing it in as a positional
> } parameter.  It has the disadvantage that it won't remove the tmp file if
> } something goes wrong.
>
> In fact the point of using =(:) is that it WILL remove the tmp file if
> something goes wrong (unless it's something completely catastrophic like
> the shell itself crashing, but in that case an explicit "rm" wouldn't
> work either).
>

Right, it's the "unless" I'm worried about:

## temp file isn't deleted on exit, so it's still there to be removed
$ ( () { local tmp=$1 ; echo $tmp ; exit 1 } =(:) ) | xargs rm --verbose
removed '/tmp/zsh9OzJL1'

## temp file is deleted with exit trap
$ ( () { local tmp=$1 ; trap "rm $tmp" INT QUIT EXIT ; echo $tmp ; exit 1 }
=(:) ) | xargs rm --verbose
rm: cannot remove '/tmp/zshhzsFQo': No such file or directory


Instead of exit traps, you can use "always" blocks:
>
>   () {
>     local tmp=$1;
>     {
>       : do stuff with $tmp
>       exit
>     } always {
>       rm $tmp
>     }
>   } =(:)
>

Cool!  ~Half my scripts have no need of POSIX-ness, so that'll come in
handy.

-- 
Best,
Ben

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: virtual files?
  2016-04-21  4:12   ` Emanuel Berg
  2016-04-21  6:58     ` Bart Schaefer
@ 2016-04-22  5:55     ` Benjamin R. Haskell
  1 sibling, 0 replies; 15+ messages in thread
From: Benjamin R. Haskell @ 2016-04-22  5:55 UTC (permalink / raw)
  To: Zsh-Users List

[-- Attachment #1: Type: text/plain, Size: 2394 bytes --]

On Thu, Apr 21, 2016 at 12:12 AM, Emanuel Berg <embe8573@student.uu.se>
wrote:

> "Benjamin R. Haskell" <zsh@benizi.com> writes:
>
> > [...]
> >   () {
> >     local tmp=$1
> >     wget -q $link -O $tmp
> >     echo -n \$
> >     grep \"answer\" $tmp | cut -d \$ -f 2 | cut -d \< -f 1
> >   } =(:)
> > }
>
> [...]
>
> Only remark is, if you do all this trouble to get
> clean code, and then name the local "tmp", it is
> almost comical.


I like to think of it as a lingering code smell.  Don't need a tmp file
after all. ;-)


[...]


> >   awk '/"answer"/' |
>
> awk instead of grep in this context should be strange
> to many who are more familiar with grep, but grep has
> the problem that many like to put colorization to it
> which can screw up parsing. If the configuration
> is in an environmental, I suppose not even giving the
> full path to the binary to bypass an alias would get
> them away. One can supply a specification, of course,
> telling grep not to use colors, but rather than doing
> that, I switched to awk as you suggested.
>

I tend to prefer awk for a few reasons:
1. Whatever I wanted to `grep` usually needs some small amount of
post-processing. (not in this case, but usually scope expands.)
2. It's often one fewer pipe than a `grep ... | cut ...`
3. In a lot of contexts it's nice that it doesn't exit non-zero even if
nothing matches.
4. Its implementations tend to be very consistent (no worries about GNU vs
non-GNU or Linux/other that often arise with other utilities), so it's a
good command to learn.


I also changed the two cut:s for tr, and date +%Y from
> the `one` syntax form into $(another).
>

I strongly favor $(another) due to its nestability.


[...]


> One interesting thing is tho I changed three programs
> out of three used, I don't think this function is
> anything "remote" to the one I originally wrote.
> A small homage to the diversity of the Linux/Unix
> tools, I suppose. But come to think of it there are
> many players in the NHL that score some ~15 goals
> every season, but that doesn't mean they cannot also
> be completely different players, physical aspects as
> well as those of skill and style...
>

I noticed that I'd changed all the tools you used, too.  It's also fun to
notice that (maybe?) 5 years ago, I probably would've used Perl for the
whole pipeline, but these days I pretty rarely fall back to it.

-- 
Best,
Ben

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2016-04-22  5:55 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-04-20  1:00 virtual files? Emanuel Berg
2016-04-20  1:27 ` Nikolay Aleksandrovich Pavlov (ZyX)
2016-04-20  2:12   ` Emanuel Berg
2016-04-20  2:31     ` Nikolay Aleksandrovich Pavlov (ZyX)
2016-04-20  4:03     ` Bart Schaefer
2016-04-20  6:06       ` Emanuel Berg
2016-04-21 22:14       ` Emanuel Berg
2016-04-22  1:08         ` Bart Schaefer
2016-04-20  3:32 ` Benjamin R. Haskell
2016-04-20 20:34   ` Bart Schaefer
2016-04-22  5:26     ` Benjamin R. Haskell
2016-04-21  4:12   ` Emanuel Berg
2016-04-21  6:58     ` Bart Schaefer
2016-04-21  8:05       ` Emanuel Berg
2016-04-22  5:55     ` Benjamin R. Haskell

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).