I need to read a list of the files from some text file, line by line, then translate it to the sequence of -a filename1 -a filename2 -a filename3.
I've tried to do this, but looks like the syntax of the setting FILES variable is wrong in that context:
files_pack: @while read -r file; do \ FILES += "-a $$file"; \ done <$(LIST_FILE) some_util $(FILES) 4 Answers
Inspired by Anton Kochkov's answer, a simple solution which will work with any shell, but fails if filenames contain whitespace or metacharacters:
files_pack: some_util $(shell printf " -a %s" $$(cat $(FILES)))This can be improved to handle filenames with whitespace or special characters other than apostrophes:
files_pack: some_util $(shell IFS="$$(printf '\n+')"; IFS="$${IFS%+}"; printf " -a '%s'" $$(cat $(FILES)))The peculiar sequence of setting IFS to newline+ and then removing the + is the only Posix-compatible way I know of to set IFS to a single newline which does not involve a command-line with a physical newline. (Simple command substitution deletes trailing newlines regardless of the setting of IFS.)
With bash, this can be simplified and made more robust, using the %q printf format (and some other bashisms to simplify):
files_pack: SHELL := /bin/bash some_util $(shell IFS=$$'\n'; printf " -a %q" $$(<$(FILES))) 2 If the LIST_FILE has one file per line, and all you need to do is prepend each line with -a, then what you want is
files_pack: some_util $$(sed 's/^/-a /' $(LIST_FILE)) 1 Shell assignments cannot have spaces around the =/+=.
Also $(FILES) is going to be expanded by make. You want "$${FILES[@]}" there.
I also modified your code to use an array instead of a string so that files with spaces/etc. in the name can work correctly.
files_pack: @while read -r file; do \ FILES+=(-a "$$file"); \ done <$(LIST_FILE) some_util "$${FILES[@]}"Though, as Jens pointed out this will not with with /bin/sh on many systems and would require telling make to use /bin/bash as the shell for this target:
files_pack: SHELL := /bin/bashor globally:
SHELL := /bin/bash 3 This works too:
FILES=$(shell cat ${LIST_FILE) FILES_OPT=$(addprefix -a,${FILES})
And this solution doesn't depend from bash, works with every generic shell, and doesn't require 'sed' to be installed.
1