7

The second line of the script only works if I trigger glob expansion by executing echo. I can't understand why. Here's the command and it's execution to give some context.

Function definition:

~/ cat ~/.zsh/includes/ascii2gif
ascii2gif () {
        setopt extendedglob
        input=$(echo ${1}(:a))
        _path=${input:h}
        input_f=${input:t}
        output_f=${${input_f}:r}.gif
        cd $_path
        nerdctl run --rm -v $_path:/data asciinema/asciicast2gif -s 2 -t solarized-dark $input_f $output_f
}

Activate function debugging for ascii2gif function..

~/ typeset -f -t ascii2gif

Debugged function execution:

~/ ascii2gif ./demo.cast
+ascii2gif:1> input=+ascii2gif:1> echo /Users/b/demo.cast
+ascii2gif:1> input=/Users/b/demo.cast
+ascii2gif:2> _path=/Users/b
+ascii2gif:3> input_f=demo.cast
+ascii2gif:4> output_f=demo.gif
+ascii2gif:5> cd /Users/b
+_direnv_hook:1> trap -- '' SIGINT
+_direnv_hook:2> /Users/b/homebrew/bin//direnv export zsh
+_direnv_hook:2> eval ''
+_direnv_hook:3> trap - SIGINT
+ascii2gif:6> nerdctl run --rm -v /Users/b:/data asciinema/asciicast2gif -s 2 -t solarized-dark demo.cast demo.gif
==> Loading demo.cast...
==> Spawning PhantomJS renderer...
==> Generating frame screenshots...
==> Combining 40 screenshots into GIF file...
==> Done.

I've tried numerous variations to try and force expansion such as input=${~1}(:a) etc, but to no avail. Any suggestions? Obviously the script works but seems sub-optimal.

3
  • The 2nd line ascii2gif () {? Commented Mar 30, 2022 at 13:20
  • And the first line ~/ cat ~/.zsh/includes/ascii2gif does? Commented Mar 30, 2022 at 13:21
  • Unrelated: setopt and variable assignments have a global effect by default. When you change options for the purposes of a function, either use setopt local_options or, usually, use emulate -L zsh so that your function will work if some options you weren't thinking about have been changed from the default. Also make variables local with local (or typeset). Also it's probably a bad idea to change the current directory in this function. Or you could run the whole function in a subshell by putting (…) around the body instead of {…} (but still keep emulate zsh). Commented Mar 30, 2022 at 20:55

2 Answers 2

5

That's because the way you're trying to use the a modifier here is for globbing, and no globbing takes place in var=WORD (because globbing, in general, can result in multiple words, so it doesn't take place in contexts that expect a single word). So you're relying on globbing taking place inside the command substitution, and then assigning the result to the variable.

Since the a modifier can be used on parameter expansion but with a different way of applying it, you can try that:

input=${1:a}

For example:

% cd /tmp
% foo() { input=${1:a}; typeset -p input; }
% foo some-file
typeset -g input=/tmp/some-file
1
  • ah, such a small think when you know the right answer - thanks Gilles
    – bryan hunt
    Commented Mar 31, 2022 at 14:42
4

/u muru's answer looks like the right way to go about this, but the reason why it's not expanding is that filename generation (globbing) does not take place in scalar assignments (it does in array assignments, because globs - in general - may return multiple matches):

From man zshoptions:

   GLOB_ASSIGN <C>
          If this option is set, filename generation  (globbing)  is  per‐
          formed on the right hand side of scalar parameter assignments of
          the form `name=pattern (e.g. `foo=*').  If the result  has  more
          than  one  word  the  parameter  will become an array with those
          words as arguments. This option is provided for  backwards  com‐
          patibility  only: globbing is always performed on the right hand
          side of array  assignments  of  the  form  `name=(value)'  (e.g.
          `foo=(*)')  and  this form is recommended for clarity; with this
          option set, it is not possible to  predict  whether  the  result
          will be an array or a scalar.

So

$ zsh -c 'f=${1}(:a); echo $f' zsh file.txt
file.txt(:a)

but

$ zsh -c 'f=(${1}(:a)); echo $f' zsh file.txt
/home/steeldriver/dir/file.txt

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .