0

问题:

我对 GNU Make 很陌生。有没有更好的方法以编程方式将统计数据集从 sas7bdat 转换为 csv 文件,并使用 GNU Make 使它们彼此同步以促进可重复的研究?你会从编码的角度以不同的方式解决这个问题,还是有更好的方法来促进可重复的研究?statTransferOptions.txt我可以在使用静态模式规则时添加额外的先决条件(即)吗?

解决方案需要:

  • 查找所有子目录中的所有 sas7bdat 文件
  • 读取 statTransfer 选项
  • 使用带有选项的 statTransfer 命令行工具将 sas7bdat 文件转换为 csv 文件
  • 鉴于 statTransfer 的当前限制,我认为这将需要两个步骤:
    • 为每个 SAS 数据文件 ( .sas7bdat)构建 statTransfer 命令文件 ( .stcmd)
    • 通过使用 stcmd 文件中的选项执行 statTransfer (st) 为每个 stcmd 文件构建 csv 文件
    • 目标 stcmd 和 csv 文件应与必备的 sas7bdat 文件位于同一子目录中
    • 如果存在新的 sas7bdat 文件或基本选项文件发生更改,则查找过期的 stcmd 和 csv 文件并更新它们

语境:

我继承了一份每年发布的大型统计报告。在前几年,分析是在 SAS 中完成的。我们现在正在使用 R。SAS Enterprise Guide 生成的一些 sas7bdat 文件无法使用sas7bdat 包正确导入。StatTransfer 是一款商业产品,具有命令行界面,并且可以将 sas7bdat 文件正确转换为 csv 文件;但是,有一些选项可以改进转换(例如,日期格式的写入)。sas7bdat 文件位于与数据集类型和年份相对应的多个子目录中。

这种方法进一步受到以下因素的推动:

克里斯托弗·甘德鲁德 (2013-06-21)。使用 R 和 RStudio 进行可重复研究(Chapman & Hall/CRC The R Series)(第 104-105 页)。查普曼和霍尔/CRC。Kindle版。

故障排除:

建议的 MAKEFILE?

RDIR := .

######
#PREP#
######
# Use BASH shell to create list of source sas7bdat files
SASDATA = $(shell find $(RDIR) -type f -name '*.sas7bdat')

# Use pattern substring functions to define variable list of filenames
# to be used as targets in recipes
STCMD_OUT = $(patsubst $(RDIR)/%.sas7bdat, $(RDIR)/%.stcmd, $(SASDATA))
CSV_OUT = $(patsubst $(RDIR)/%.sas7bdat, $(RDIR)/%.csv, $(SASDATA))

#########
#TARGETS#
#########

all: $(STCMD_OUT) $(CSV_OUT)

# I think the name "static pattern rules" is misleading
# but I found this to be helpful:
# http://www.gnu.org/software/make/manual/make.html#Static-Pattern

# can I add statTransferOptions.txt as a pre-requisite while using static pattern rules?

$(STCMD_OUT): $(RDIR)/$(@D)/%.stcmd: $(RDIR)/$(@D)/%.sas7bdat
    cp $(RDIR)/statTransferOptions.txt $@
    echo copy $(RDIR)/$< delim $(RDIR)/$(basename $<).csv -v >> $@
    echo quit >> $@

$(CSV_OUT): $(RDIR)/$(@D)/%.csv: $(RDIR)/$(@D)/%.stcmd
    st $(RDIR)/$<

clean:
    rm $(STCMD_OUT)
    rm $(CSV_OUT)

从 SO 输入后修改的 MAKEFILE:

RDIR := .

######
#PREP#
######
# Create list of source sas7bdat files
SASDATA := $(shell find $(RDIR) -type f -name '*.sas7bdat')

STCMD_OUT := $(patsubst $(RDIR)/%.sas7bdat, $(RDIR)/%.stcmd, $(SASDATA))
CSV_OUT := $(patsubst $(RDIR)/%.sas7bdat, $(RDIR)/%.csv, $(SASDATA))

#########
#TARGETS#
#########

all: $(STCMD_OUT) $(CSV_OUT)

$(STCMD_OUT): %.stcmd: %.sas7bdat statTransferOptions.txt
    cp $(RDIR)/statTransferOptions.txt $@
    echo copy $(RDIR)/$< delim $(RDIR)/$(basename $<).csv -v -y >> $@
    echo quit >> $@

$(CSV_OUT): %.csv: %.stcmd
    st $(RDIR)/$<

clean:
    rm $(STCMD_OUT)
    rm $(CSV_OUT)

但是,正确的选择可能是调试 CRAN sas7bdat 包,以便整个工具链可用,而不是调用专有的 statTransfer。

4

1 回答 1

2

在 SO 中,我们通常没有时间或精力(或者,通常是兴趣)去阅读相关的论文、选项、替代方案等。如果您简单而清楚地指定您遇到问题的代码(在此情况下,提供的makefile很棒),您遇到的确切问题,包括错误消息或不正确的输出(这在您的问题中并不明显),您想要发生的事情没有发生,因为这并不总是很清楚,也许还有你尝试过但没有奏效的任何其他想法或方向。

我不确定您遇到的确切问题是什么,但我发现您的 makefile 存在许多问题。首先,这将起作用,但效率非常低:

SASDATA = $(shell find $(RDIR) -type f -name '*.sas7bdat')

你应该在:=这里使用赋值的形式。可能您应该在设置时也使用它STCMD_OUTCSV_OUT尽管这不太重要。

但最重要的是,这些规则并不正确:

$(STCMD_OUT): $(RDIR)/$(@D)/%.stcmd: $(RDIR)/$(@D)/%.sas7bdat

您不能$@在目标或先决条件列表中使用自动变量(或其任何替代形式)。自动变量仅在规则的配方中定义。您可以为此使用二级扩展,但我不确定您为什么要这样做。为什么不直接使用:

$(STCMD_OUT): %.stcmd: %.sas7bdat

? 其他静态模式规则也一样?

至于您的问题,是的,添加额外的先决条件(例如statTransferOptions.txt静态模式规则)是完全可以的。

于 2013-12-16T17:33:01.910 回答