39

I'm working in , but I'm sure that instructions will also be helpful.

I need to have a for loop that goes through the values stored in the array lw and then launches a shell script, based on the name value stored in the array.

So far, this is what I've come up with:

$lw=('plugin1' 'plugin2' 'plugin3')

for i in $lw;
  do . ~/Library/Rogall/plugins/$lw[$i]/lw.prg end;
done

Running this gives me an error saying that it can't find ~/Library/Rogall/plugins//lw.prg. It appears as if it's ignoring my variable all together.

Any ideas where I've messed up?

1
  • 2
    Try echo $i to see what it contains. Commented Jun 4, 2012 at 20:08

4 Answers 4

69

It's actually much simpler than that:

lw=('plugin1' 'plugin2' 'plugin3')

for i in $lw; do
  . ~/Library/Rogall/plugins/$i/lw.prg end
done

In summary:

  • Assign to foo, not $foo (the shell would try to expand $foo and assign to whatever it expands to; typically not useful)
  • Use the loop variable directly; it contains the array value rather than the index
Sign up to request clarification or add additional context in comments.

4 Comments

That makes so much sense! Thank you!
Or just for i ($lw) . ~/Library/Rogall/plugins/$i/lw.prg end
Not that in the general case, for i in $array would skip the empty elements. You'd need for i in "$array[@]" or for i in "${(@)array}" to preserve the empty ones (or the ksh/bash-compatible syntax: for i in "${array[@]}").
@theonlygusti you mean $lw? Simply put in the ('plugin1' 'plugin2' 'plugin3') directly in place of $lw.
30

Why bother using the array? This can be done in portable sh very easily:

lw='plugin1 plugin2 plugin3'

for i in $lw;
  do . ~/Library/Rogall/plugins/$i/lw.prg end
done

Note that for this to work in zsh, you need to make zsh do the right thing with: set -o shwordsplit

8 Comments

Not everything is about being as portable as can be, especially if it's to be run on a Mac (judging by the directory names). Also your solution fails for the generic case in which there might be spaces in each word.
@Moritz This is not a generic case, but a specific case in which there are no spaces in the filenames. Portability may not always be necessary, but it is always a desirable goal. And this solution works just fine on a Mac.
@Moritz And spaces in filenames are an abomination! Also, Jan's solution fails if there is any whitespace in the filename.
How do you know that the plugin directories don't contain spaces? The names presented in the original post are so generic that it's safe to assume that they're not the actual names. Jan's solution will work as it is on zsh with certain settings. Even if not it can be made with two trivial changes. Your solution cannot be used with white spaces easily. But alas, things like "spaces in file names are an abomination" is so incredibly up for debate that it's not even funny. But let's stop here and agree to disagree.
It isn't portable if it relies on the ZSH defaults being changed when the context is likely a .zshrc file. Array is a better solution.
|
13

I had a problem where a loop like this one

for i in (1 2 3 4); do echo $i; done

was repeatedly not working as I wanted. I would get errors like zsh: unknown file attribute: 1, or outputs like

1 2 3 4

no matter how I re-contorted it, instead of my desired

1
2
3
4

To get my desired behaviour I had to remove the in keyword from the loop definition

for i (1 2 3 4); do echo $i; done
1
2
3
4

Comments

2

For others who end up here wrestling with shell scripts, arrays and spaces in filenames...... like my file list below;

$ ls *.meta
20160324 1850 - ABC - Clarke And Dawe.ts.meta
20160706 1515 - 9Gem - Agatha Christie's Poirot.ts.meta
20181213 0155 - 10 BOLD - Star Trek_ The Next Generation.ts.meta
20210424 1927 - ABCTV HD - The Durrells.ts.meta
20210501 1927 - ABCTV HD - The Durrells.ts.meta
20210818 1930 - SBS ONE HD - Tony Robinson's World By Rail.ts.meta

After a lot of searching and trying different approaches this worked out to be the least problematic and worked on MacOS 10.15

eval "list=( $(find . -name "*.ts" -exec echo \"{}\" \;) )"
for name in "${list[@]}"
do
res=`mediainfo --Output=''Video\;\%Width\%:%Height\%'' "$name"`
echo ${name} :: $res
sed -i .bak -e 5s/\;[[:digit:]]*:[[:digit:]]*// -e 5s/$/\;$res/ "$name.meta" 
done

Ignoring the internals of what I was trying to achieve, the critical aspects were using eval and wrapping double quotes around the filename in the echo within the find. (What was I doing? I was pulling the resolution out of Enigma2 PVR recordings and writing it into line 5 of the related meta data file)

Thanks to all those who posted their own knowledge on the various issues that shell scripting generates.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.