bash - forcing globstar asterisk expansion when passed to loop

I am attempting to write a script that tried to use globstar expressions to execute a command (for example ls)

#!/usr/bin/env bash

shopt -s globstar nullglob
DISCOVERED_EXTENSIONS=$(find . -type f -name '*.*' | sed 's|.*\.||' | sort -u | tr '\n' ' ' | sed "s| | ./\**/*.|g" | rev | cut -c9- | rev | echo "./**/*.$(</dev/stdin)")

IFS=$'\n'; set -f
for f in $(echo $DISCOVERED_EXTENSIONS | tr ' ' '\n'); do
  ls $f;
done

unset IFS; set +f
shopt -u globstar nullglob

The script output is:

ls: ./**/*.jpg: No such file or directory
ls: ./**/*.mp4: No such file or directory

It is passing ls "./**/*.avi" instead of ls ./**/*.avi (no variable expansion). I attempted to use eval, envsubst and even used a custom expand function, to no avail

The result of echo "$DISCOVERED_EXTENSIONS" is:

./**/*.jpg ./**/*.mp4

What changes can be recommended so that value of $f is the result of glob expansion and not the expression itself?

EDIT: I'm keeping the question up as I have resolved my problem by not using globstar at all which solves my immediate problem but doesn't solve the question.

As pynexj points out, the set -f un-does shopt -s globstar nullglob so that makes the script I've written as non-functional 'cause removing set -f breaks this script

Upvotes: 2

Views: 893

Answers (1)

KamilCuk
KamilCuk

Reputation: 141930

$f is the result of glob expansion

The result of glob expansion is a list of arguments. It could be saved in an array. Saving it is just calling a subshell and transfering data.

mapfile -t -d '' arr < <(bash -c 'printf "%s\0" '"$f")
ls "${arr[@]}"

Notes:

  • Do not do for i in $(....). Use a while IFS= read -r loop. Bashfaq how to read a stream line by line.
  • I have no idea what is going on at that DISCOVERED_EXTENSIONS long line, but I would find . -maxdepth 1 -type f -name '*.*' -exec bash -c 'printf "%s\n" "${0##*.}"' {} \; | sort -u.
  • I usually recommend using find instead of glubulation and working on pipelines/streams. I guess I would write it as: find . -maxdepth 1 -type f -name '*.*' -exec bash -c 'printf "%s\n" "${0##*.}"' {} \; | sort -u | while IFS= read -r ext; do find . -type f -name "*.$ext" | xargs -d '\n' ls; done

Upvotes: 1

Related Questions