I want to loop over entries in a directory without using ls or having to work with full paths. I tried `for file in $(ls folder)`, but command substitution hides the failure when the directory does not exist. A glob such as `folder/*` gives paths rather than bare names, so I wondered whether Bash can return only the filename portion directly. I also want options such as `shopt -s failglob` and `set -o pipefail` to apply automatically to every Bash script, even when I forget to enable them.
4 Answers
There is a `BASH_ENV` variable that Bash can use to source a file for non-interactive shells, and it could be set through your login environment. However, relying on global shell settings is generally a bad idea: each script should enable the options it depends on, such as `set -o pipefail` or `shopt -s failglob`, so its behavior is explicit and predictable.
For a missing or empty directory, enable `nullglob` if you want the loop to run zero times: `shopt -s nullglob; for path in folder/*; do name=${path##*/}; ...; done`. If you prefer that an unmatched glob be an error, use `failglob` and handle the resulting failure explicitly. Avoid parsing `ls`; it is not reliable for arbitrary filenames.
If filenames may contain newlines or other unusual characters, use a NUL-delimited `find` result with `-print0` and read it with `readarray -d ''` or a `while IFS= read -r -d ''` loop. For ordinary shell loops, quoting the expanded variable—such as `"$path"`—is essential.
A glob naturally expands to paths, but you can remove the directory portion with Bash parameter expansion: `for path in folder/*; do name=${path##*/}; printf '%sn' "$name"; done`. The `##*/` expression strips everything through the last slash. If you want to process only regular files, add `[[ -f $path ]] || continue` inside the loop.

You can also change into the directory and loop over `*`, but using the full path is usually safer because it avoids changing the script's working directory.