Interesting #ShellScripting quandary:

(solution below)

I'm uncertain how shells delimit filename variables internally.

I have a shell (bash) function that loops through a set of PDF files, opening them in zathura in a "suckless" tabbed window (so that the PDFs always open within the same window, so I can just hit q to zip through them one-at-a-time.

Here is my variable declaration:

local files=${*-*.[pP][dD][fF]}

But for simplicity, you could just imagine it to be:

files=*

Then I'm doing a

for f in $files; do

I'm wanting to print a status line for each item viewed, so I have an idea how many more there are to go, so I'm using this:

echo "[[$f]] ($count/$tot)"

And of course, there's a ((count++)) at the beginning of the loop.

But how to get the total ($tot)??

echo $files |wc -l will always result in 1, as does echo "$files" |wc -l

What I ended up doing was just creating a

for f in $files; do ((tot++)); done

One-liner loop before the actual loop, just to get a total.

Is there a better way?

Am I missing something really obvious?

Solution, courtesy of @khm

Use an array!

local files=(${*-*.[pP][dD][fF]}) echo "[[$f]] ($count/${#files[@]})"
use arrays.

$ files = ("file1" "file2" "file3")

$ echo ${files[0]}
file1

$ echo ${#files[@]} # get count
3

@khm

Wouldn't that require a for loop to load the array, though?

Or is there an easy way to do something like

typeset -a files=*

(that would actually read it into an array, rather than schlorping it all into ${files[0]})?

files=(*-*.[pP][dD][fF]) should load the array

glob's gonna glob

@rl_dane

wc -w

@seachanged

Ah, but the files contain spaces. I know, UNIXer's nightmare. XD

@rl_dane @khm

I'm uncertain how shells delimit filename variables internally.

… I don’t think I understand the question. (This probably is because this question comes from a mental model of the shell that isn’t accurate.) Could you explain what exactly you think it is you don’t understand?

@mirabilos @khm

I think I wasn't realizing that when you do something like files=*, it's literally just putting "*" in the variable $files, which gets evaluated when you evaluate the variable, not when you assign it.

@rl_dane @khm indeed:

$ files=* $ typeset -p files typeset files='*'

Use the proper inspection tool for that ☻ (typeset -f for functions)

@rl_dane @khm (actually, ā€œgets evaluated when you evaluate the variableā€ is also imprecise: it gets expanded exactly when the result of the expansion involving the files variable is subjected to globbing; see the various stages of command expansion and word splitting in the POSIX standard)