On Sun, Feb 09, 2025 at 06:35:38 +0700, Robert Elz wrote: > ps: there is almost never a good excuse to use non-standard sh > extensions (bash's, or any other shells), when writing a standard > conforming script would allow any Bourne shell variant to > work, and that's certainly the case here, and in most other cases.
You really want bash's ${var//search/replace} feature for the renaming step, so as long as you're already using that, you might as well use any other bash features that make your job easier. For the problem as stated (no recursion), we can discard the "ls" command, the temporary file that holds the list of files, and all variations of the pipeline. There's no stdin conflict, so we don't need to open FD 3. The only bash extensions we really want, then, are the parameter expansion for the renaming step, and "read -p" for the prompt. We could use case instead of [[ for checking the user's input, but why? We're already using two bash extensions, and [[ is nicer to use. for f in *[[:space:]]*; do read -r -p "Fix <$f>? " yn if [[ $yn = [Yy]* ]]; then mv -- "$f" "${f//[[:space:]]/_}" fi done Everything else was a demonstration of how the code might look if we were solving some *other* problem, slightly similar to the original, for educational purposes. If I were going to write this in POSIX sh, the read -p could be replaced with printf + read, and the [[ with case, but the name alteration becomes *ugly*. for f in *[[:space:]]*; do printf 'Fix <%s>? ' "$f" read -r yn case $yn in [Yy]*) new=$( printf %s "$f" | tr '[:space:]' _ printf x ) new=${new%x} mv -- "$f" "$new" ;; esac done Forking multiple processes just to replace some characters in a string is sad. I'd much rather use bash for this. Or just use the perl rename script that's been available on most Linux distributions for ages: prename 's/\s/_/g' *[[:space:]]* P.S. Yeah, I could have skipped the "printf x" and ${new%x} steps here, because it's not possible for tr's output to end with a newline (even if the original filename does), because the newline is replaced with a _ character. Or at least, that's what happens in any normal locale. But I left them in because, again, someone might adapt this code to a *slightly different* problem where the data stream could end with newline character(s), which would be destroyed by the command substitution.