Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: virtual files?



On Tue, Apr 19, 2016 at 9:00 PM, Emanuel Berg <embe8573@xxxxxxxxxxxxx>
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


Messages sorted by: Reverse Date, Date, Thread, Author