1

This is more of a mental practice with bash syntax. I would invite you to take this as a puzzle so we may solve this together. Or as a challenge in understanding bash.

The Problem

For instance, I have 3 files in a folder ./etc:

  • ./etc
    • foo.txt.example
    • bar.txt.example
    • hello world.txt.example (yes, there is space in this file)

I have constructed the target to do these target, based on the above files, works:

make "etc/foo.txt"
make "etc/bar.txt"
make "etc/hello world.txt"

So in theory, I can construct a command like this to run all the targets:

make "etc/foo.txt" "etc/bar.txt" "etc/hello world.txt"

Here comes my question: Can you construct a bash script that search all ./etc/*.txt.example filenames and construct the above command?

Requirement

  1. The answer need to be in the form of a bash command or preferable Makefile target definition;
  2. It need to be run-able in most Linux environment by default. It should not require installation of uncommon packages.

What I have Tried

I have already figure out a way in Makefile to get all filenames above:

txt:
    for fn in "etc/*.txt.example"; do \
        echo "etc/$$(basename -s ".example" "$$fn")"; \
    done

Which basically means running this in bash:

for fn in "etc/*.txt.example"; do \
    echo "etc/$(basename -s ".example" "$fn")"; \
done

that gives the following output:

etc/foo.txt
etc/bar.txt
etc/hello world.txt

If you use this loop's output as input of another command, the command seems to treat all space as seperator of arguments. So this:

make $(for fn in "etc/*.txt.example"; do \
    echo "etc/$(basename -s ".example" "$fn")"; \
done)

is practically this:

make "etc/foo.txt" "etc/bar.txt" "etc/hello" "world.txt"

Is there a way to turn the loop's output into arguement that properly preserves the spaces?

2

You could use arrays:

# Get all example files in an array
examples=(etc/*.example)
# Strip the .example suffix from every element of the array
make "${examples[@]%.example}"

Or if you have GNU find, sed and xargs (with nul-delimiter support, that is):

find etc -iname '*.example' -print0 | sed -z 's/\.example$//' | xargs -0 make
2

Creating a nul-delimited list of file names and passing them to make via xargs:

for name in /etc/*.txt.example; do
    printf '%s\0' "${name%.example}"
done | xargs -0 make
0

First create the example files and next create

set etc/*.tbl.example
N="shift $#"
for arg
do
   $N; N=;
   set X ${1+"$@"} "$(expr "$arg" '\(.*\).example')"; shift       
done
# and then...
make ${1+"$@"}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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