我是make
新手,所以请随意更正我对此问题的语法。
我想创建一个下载一堆压缩文件的makefile,解压缩它们并对它们做一些事情。这是我的玩具示例:
my_dir/*.txt.gz:
echo "# obtaining data"
mkdir -p my_dir
echo 1 > my_dir/file1.txt
gzip my_dir/file1.txt
echo 2 > my_dir/file2.txt
gzip my_dir/file2.txt
my_dir/*.txt: my_dir/*.txt.gz
echo "# unzipping data"
parallel gzip -d ::: my_dir/*.txt.gz
final.txt: my_dir/*.txt
echo "# doing something with data"
cat my_dir/*.txt > $@
clean_my_dir:
rm -rf my_dir
rm -f final.txt
当我运行make final.txt
时,我得到了我期望的结果(final.txt
包含1\n2
),但如果我再次运行make final.txt
(不运行make clean_my_dir
)我得到一个错误:
make final.txt
echo "# obtaining data"
# obtaining data
mkdir -p my_dir
echo 1 > my_dir/file1.txt
gzip my_dir/file1.txt
echo 2 > my_dir/file2.txt
gzip my_dir/file2.txt
echo "# unzipping data"
# unzipping data
parallel gzip -d ::: my_dir/*.txt.gz
echo "# unzipping data"
# unzipping data
parallel gzip -d ::: my_dir/*.txt.gz
gzip: can't stat: my_dir/*.txt.gz (my_dir/*.txt.gz.gz): No such file or directory
make: *** [my_dir/file2.txt] Error 1
我确信我在设置目标和先决条件方面犯了错误:我希望final.txt
包含file1.txt
和file2.txt
的内容,但是这些文件最初是压缩的。如果有压缩文件,我如何告诉make
调用gzip
,如果未压缩文件可用,我怎么告诉他们什么都不做?
答案 0 :(得分:2)
经过一些实验后,我创建了以下makefile:
COMPRESSED_DIR = my_dir
UNCOMPRESSED_DIR = temp_dir
DEPS = \
$(UNCOMPRESSED_DIR)/file1.txt \
$(UNCOMPRESSED_DIR)/file2.txt
##
## Recipes how to obtain compressed files
## (may propably not so trivial in your intended application)
##
$(COMPRESSED_DIR)/file1.txt.gz:
@echo ""
@echo "# obtaining $@"
mkdir -p $(COMPRESSED_DIR)
echo 1 > $(COMPRESSED_DIR)/file1.txt
gzip $(COMPRESSED_DIR)/file1.txt
$(COMPRESSED_DIR)/file2.txt.gz:
@echo ""
@echo "# obtaining $@"
mkdir -p $(COMPRESSED_DIR)
echo 2 > $(COMPRESSED_DIR)/file2.txt
gzip $(COMPRESSED_DIR)/file2.txt
## or alternatively:
#$(COMPRESSED_DIR)/%.txt.gz:
# @echo ""
# @echo "# obtaining $@"
# mkdir -p $(COMPRESSED_DIR)
# echo $* > $(COMPRESSED_DIR)/$*.txt
# gzip $(COMPRESSED_DIR)/$*.txt
##
## Recipe to unpack compressed files
##
$(UNCOMPRESSED_DIR)/%.txt: $(COMPRESSED_DIR)/%.txt.gz
@echo ""
@echo "# unpacking $<..."
mkdir -p $(UNCOMPRESSED_DIR)
gzip -c -d $< > $@
##
## Recipe to make final.txt
##
final.txt: $(DEPS)
@echo ""
@echo "# doing something with data"
cat $(UNCOMPRESSED_DIR)/*.txt > final.txt
##
## Recipe to clean
##
clean:
rm -rf $(COMPRESSED_DIR)
rm -rf $(UNCOMPRESSED_DIR)
rm -f final.txt
如前所述,gzip会删除txt.gz文件,因此如果再次制作final.txt,则会重新执行创建txt.gz文件的方法。
我所做的是将解压缩的txt.gz文件放在一个单独的目录中,并强制gzip在解压缩时保留原始文件。这会导致以下行为:
如果第一次调用,将创建并解压缩txt.gz文件并创建final.txt:
# obtaining my_dir/file1.txt.gz
mkdir -p my_dir
echo 1 > my_dir/file1.txt
gzip my_dir/file1.txt
# unpacking my_dir/file1.txt.gz...
mkdir -p temp_dir
gzip -c -d my_dir/file1.txt.gz > temp_dir/file1.txt
# obtaining my_dir/file2.txt.gz
mkdir -p my_dir
echo 2 > my_dir/file2.txt
gzip my_dir/file2.txt
# unpacking my_dir/file2.txt.gz...
mkdir -p temp_dir
gzip -c -d my_dir/file2.txt.gz > temp_dir/file2.txt
# doing something with data
cat temp_dir/*.txt > final.txt
如果再次调用(没有make clean),输出将是make:
final.txt'是最新的。如果删除$(DEPS)文件,将重新解压缩相应的txt.gz文件。如果删除了.txt.gz文件,将重新创建.txt.gz文件并重新解压缩(因为它比现有的.txt文件更新)。
另外,如果您已经获得了要处理的所有* .txt.gz文件(如果缺少makefile,则不必创建它们),您可以使用以下makefile:
COMPRESSED_DIR = my_dir
UNCOMPRESSED_DIR = temp_dir
# get a list of all *.txt.gz files within $(COMPRESSED_DIR)
ARCHIVES = $(wildcard $(COMPRESSED_DIR)/*.txt.gz)
# do some magic to modify $(ARCHIVES) into a list of *.txt files to produce
DEPS = $(subst $(COMPRESSED_DIR),$(UNCOMPRESSED_DIR),$(subst .txt.gz,.txt,$(ARCHIVES)))
##
## Recipe to unpack compressed files
##
$(UNCOMPRESSED_DIR)/%.txt: $(COMPRESSED_DIR)/%.txt.gz
@echo ""
@echo "# unpacking $<..."
mkdir -p $(UNCOMPRESSED_DIR)
gzip -c -d $< > $@
##
## Recipe to make final.txt
##
final.txt: $(DEPS)
@echo "Archives:"
@echo $(ARCHIVES)
@echo ""
@echo "Deps:"
@echo $(DEPS)
@echo ""
@echo "# doing something with data"
cat $(UNCOMPRESSED_DIR)/*.txt > final.txt
##
## Recipe to clean
##
clean:
rm -rf $(UNCOMPRESSED_DIR)
rm -f final.txt
此makefile将COMPRESSED_DIR中的所有* .txt.gz文件解压缩到UNCOMPRESSED_DIR,并将所有* .txt文件解压缩到final.txt。
答案 1 :(得分:1)
你可以一步完成枪械冲刺:
my_dir:
[ -d $@ ] || mkdir -p $@
my_dir/%.txt.gz: my_dir
@echo "# obtaining data for $@"
echo $* | gzip -c > $@
final.txt: my_dir/*.txt.gz
@echo "# doing something with data for $@"
gunzip -c $+ > $@
clean:
rm -rf my_dir final.txt
依赖关系my_dir/*.txt.gz
意味着final.txt
将来自当时恰好存在的任何匹配文件(当没有匹配文件时它将失败)。为确保文件在不存在时生成,您需要明确列出它们,例如(if GNU Make is used)
final.txt: $(foreach x,1 2 3 4 5 6 7 8,my_dir/$x.txt.gz)