2

I am trying to create a find command options string using entries from an array but on the last entry of the array I would like to add a different string.

EXT=(sh mkv txt)

EXT_OPTS=(-iname)

# Now build the find command from the array
for i in "${EXT[@]}"; do
    #echo $i
    EXT_OPTS+=( "*.$i" -o -iname)
done

cheers

EDIT:

So now I am going with:

#!/bin/bash

EXT=(sh mkv txt)

EXT_OPTS=()
# Now build the find command from the array
for i in "${EXT[@]}"; do
    EXT_OPTS+=( -o -iname "*.$i" )
done

# remove the first thing in EXT_OPTS
EXT_OPTS=( "${EXT_OPTS[@]:1}" )

# Modify to add things to ignore:

EXT_OPTS=( "${EXT_OPTS[@]:-1}" )
EXT_OPTS=( '(' "${EXT_OPTS[@]}" ')' ! '(' -iname "*sample*" -o -iname "*test*" ')' )

#echo "${EXT_OPTS[@]}"

searchResults=$(find . -type f "${EXT_OPTS[@]}")

echo "$searchResults"

for me produces this:

./Find2.sh
./untitled 2.sh
./countFiles.sh
./unrar.sh
./untitled 3.sh
./untitled 4.sh
./clearRAM.sh
./bash_test.sh
./Test_Log.txt
./untitled.txt
./Find.txt
./findTestscript.sh
./untitled.sh
./unrarTest.sh
./Test.sh
./Find.sh
./Test_Log copy.txt
./untitled 5.sh
./IF2.sh
  • @Jesse_b sorry edited to include the array. I'm just testing it on whats in the current folder and then use it somewhere else when its working correctly – madmiddle Feb 8 at 19:26
  • Can you show example input and output? – ctrl-alt-delor Feb 8 at 20:19
  • @ctrl-alt-delor as in where I finally use the string ? and what i get out ? – madmiddle Feb 8 at 20:23
  • Yes. As in what you put in, and what you get out. (Maybe this script has no input, that is fine. I suspect it may not.) – ctrl-alt-delor Feb 8 at 20:27
  • @ctrl-alt-delor edited post to include full code and the result for me. – madmiddle Feb 8 at 21:16
1

Add the options in another order, then delete the first element:

EXT=(sh mkv txt)

EXT_OPTS=()
# Now build the find command from the array
for i in "${EXT[@]}"; do
    EXT_OPTS+=( -o -iname "*.$i" )
done

# remove the first thing in EXT_OPTS
EXT_OPTS=( "${EXT_OPTS[@]:1}" )

If you don't use $@ for anything, it's neater looking:

EXT=(sh mkv txt)

# Empty $@
set --

# Now build the find command from the array
for i in "${EXT[@]}"; do
    set -- -o -iname "*.$i"
done

# remove the first thing in $@
shift

# assign to EXT_OPTS (this would be optional, you could just use "$@" later)
EXTS_OPTS=( "$@" )

I prefer adding -o -iname "*.$i" to the intermediate array, because "*.$i" -o -iname is difficult to read. Adding -o -iname "*.$i" to $@ also makes it really easy to just shift off the first -o after the loop.


To combine with a few exclusions (names to ignore):

extensions=( sh mkv txt )
ignore_patterns=( '*sample*' '*test*' )

include=()
# Now build the find command from the array
for ext in "${extensions[@]}"; do
    include+=( -o -iname "*.$ext" )
done

# Do the ignore list:
ignore=()
for pattern in "${ignore_patterns[@]}"; do
    ignore=( -o -iname "$pattern" )
done

# combine:
EXT_OPTS=( '(' "${include[@]:1}" ')' ! '(' "${ignore[@]:1}" ')' )

Note the parentheses added to sort out the precedence of the tests.

  • I've edited the post to include the next bit which is to exclude files with 'test' and 'sample' in the file name. It doesn't seem to work if the either of those words are at the front of the filename. – madmiddle Feb 8 at 20:20
  • @madmiddle See updated answer. – Kusalananda Feb 8 at 20:44
  • Thank you fella all working as i'd hoped. – madmiddle Feb 8 at 21:15
1

It will be easiest just to fix the array after the fact. After done, adding

unset 'EXT_OPTS[-1]'
unset 'EXT_OPTS[-1]'

will remove the last two values (-o and -iname), and then you can add others if you want (or just replace them to begin with).

It might be slightly easier still just to add a redundant condition:

EXT_OPTS+=( "*.${EXT[0]}" )

if your real situation is a bit more complicated, but for this one I would just fix it as above.

  • @michealHomer that simple. wow thank you. I needed the last parts to be remove and then add the options to ignore files with 'sample' and 'test' in them – madmiddle Feb 8 at 19:58
0

Is there a way of determining the last entry when looping through an array?

Just to answer the question as literally stated, I don't think you can do that directly. But you could of course count the elements while looping and compare that against the array size:

test=(foo bar blah qwerty)
count=${#test[@]}
n=1
for x in "${test[@]}"; do
   last=""
   if [[ $((n++)) -eq count ]]; then
        last=" (last)"            # last element, add a note about that
   fi
   printf "%s%s\n" "$x" "$last"
done

Of course in your case, you could also make the first item the exceptional one.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.