在make 4.2之前,如何获取$(shell命令)的退出状态和输出?

在make 4.2之前,如何获取$(shell命令)的退出状态和输出?,shell,makefile,return,return-value,Shell,Makefile,Return,Return Value,在上添加了变量.SHELLSTATUS。但是我的大多数linux都使用make版本4.1。如何在旧版本的make上获取make$(shell…)命令的退出状态和输出结果 使用make 4.2,我可以做到: newmake: printf '%s\n' "$(shell command && \ ( printf 'Successfully created the zip file!\n'; exit 0 ) || \ ( printf 'E

在上添加了变量
.SHELLSTATUS
。但是我的大多数linux都使用make版本
4.1
。如何在旧版本的make上获取make$(shell…)命令的退出状态和输出结果

使用make 4.2,我可以做到:

newmake:
    printf '%s\n' "$(shell command && \
        ( printf 'Successfully created the zip file!\n'; exit 0 ) || \
        ( printf 'Error: Could not create the zip file!\n'; exit 1 ) )"
    printf 'Exit status: '%s'\n' "${.SHELLSTATUS}"
正确运行的:

printf '%s\n' "Successfully created the zip file!"
Successfully created the zip file!
printf 'Exit status: '%s'\n' "0"
Exit status: 0
printf '%s\n' "Successfully created the zip file!"
Successfully created the zip file!
printf 'Exit status: '%s'\n' "1"
Exit status: 1
但是,如果我使用make 4.1或更高版本,则没有
.SHELLSTATUS
变量。然后,我尝试定义自己的
.SHELLSTATUS
变量,如下所示:

oldmake:
    printf '%s\n' "$(shell command && \
        ( printf 'Successfully created the zip file!\n'; $(eval exit_status := 0) echo ${exit_status} > /dev/null ) || \
        ( printf 'Error: Could not create the zip file!\n'; $(eval exit_status := 1) echo ${exit_status} > /dev/null ) )"
    printf 'Exit status: '%s'\n' "${exit_status}"
但是,它不能正确运行:

printf '%s\n' "Successfully created the zip file!"
Successfully created the zip file!
printf 'Exit status: '%s'\n' "0"
Exit status: 0
printf '%s\n' "Successfully created the zip file!"
Successfully created the zip file!
printf 'Exit status: '%s'\n' "1"
Exit status: 1
如您所见,正确的消息已打印,但退出状态应为
0
,而不是
1

通知 消息
成功创建了zip文件
错误:无法创建zip文件仅用于说明,不能在
$(shell…
之外使用。shell中有一个功能齐全的
Python
脚本,它将结果输出到屏幕:

define NEWLINE


endef

define RELEASE_CODE
from __future__ import print_function
import os
import zipfile

version = "${version}"
if not version:
    print( "Error: You need pass the release version. For example: make release version=1.1", end="@NEWNEWLINE@" )
    exit(1)

CURRENT_DIRECTORY = os.path.dirname( os.path.realpath( __file__ ) )
print( "Packing files on %s" % CURRENT_DIRECTORY, end="@NEWNEWLINE@" )

file_names = []
initial_file_names = [
    "Makefile",
    "build.bat",
    "fc-portuges.def",
    os.path.join("setup", "makefile.mk"),
    os.path.join("setup", "scripts", "timer_calculator.sh"),
]

for direcory_name, dirs, files in os.walk(CURRENT_DIRECTORY):

    if ".git" in direcory_name:
        continue

    for filename in files:
        filepath = os.path.join( direcory_name, filename )

        if ".git" in filepath or not ( filepath.endswith( ".tex" )
                or filepath.endswith( ".bib" )
                or filepath.endswith( ".pdf" ) ):
            continue

        file_names.append( filepath )

for filename in initial_file_names:
    filepath = os.path.join( CURRENT_DIRECTORY, filename )
    file_names.append( filepath )

zipfilepath = os.path.join( CURRENT_DIRECTORY, version + ".zip" )
zipfileobject = zipfile.ZipFile(zipfilepath, mode="w")
zipfilepathreduced = os.path.dirname( os.path.dirname( zipfilepath ) )

try:
    for filename in file_names:
        relative_filename = filename.replace( zipfilepathreduced, "" )
        print( relative_filename, end="@NEWNEWLINE@" )
        zipfileobject.write( filename, relative_filename, compress_type=zipfile.ZIP_DEFLATED )

except Exception as error:
    print( "", end="@NEWNEWLINE@" )
    print( "An error occurred: %s" % error, end="@NEWNEWLINE@" )
    exit(1)

finally:
    zipfileobject.close()

print( "", end="@NEWNEWLINE@" )
print( "Successfully created the release version on:@NEWNEWLINE@  %s!" % zipfilepath , end="" )
endef

all:
    printf '%s\n' "$(shell echo \
        '$(subst ${NEWLINE},@NEWLINE@,${RELEASE_CODE})' | \
        sed 's/@NEWLINE@/\n/g' | python - && \
        printf 'Successfully created the zip file!\n' || \
        printf 'Error: Could not create the zip file!\n' )" | sed 's/@NEWNEWLINE@/\n/g'
现在它运行正常了,但是我缺少python退出代码,可以用这个
来修复它。SHELLSTATUS

all:
    printf '%s\n' "$(shell echo \
        '$(subst ${NEWLINE},@NEWLINE@,${RELEASE_CODE})' | \
        sed 's/@NEWLINE@/\n/g' | python - && \
        ( printf 'Successfully created the zip file!\n'; exit 0 ) || \
        ( printf 'Error: Could not create the zip file!\n'; exit 1 ) )" | sed 's/@NEWNEWLINE@/\n/g'
    exit "${.SHELLSTATUS}"
但是,它只适用于make版本
4.2
或更高版本

相关的:


  • 我通过创建一个文件成功地做到了这一点:

    fixedmake:
        printf '%s\n' "$(shell command && \
            printf 'Successfully created the zip file!\n' || \
            ( printf 'Error: Could not create the zip file!\n'; \
                printf 'error\n' > /tmp/has_errors ) )"
    
        if [ -e /tmp/has_errors ]; \
            then printf 'Exit with errror\n'; \
            rm /tmp/has_errors; \
        else \
            printf 'Exit with success\n'; \
        fi;
    
    -->

    printf“%s\n”已成功创建zip文件
    成功创建了zip文件!
    如果[-e/tmp/有错误]\
    然后printf'Exit with error\n'\
    rm/tmp/有错误\
    否则\
    printf“成功退出\n”\
    fi;
    成功退出
    

    有更好的选择吗?

    我完全不明白你为什么要使用
    $(shell…
    )。这太复杂了,太没有意义了。
    $(shell…
    的唯一效果是它在运行任何配方之前展开。但你从来没有试图利用它。相反,将脚本直接移动到配方中看起来很自然

    例如,考虑这一点:

    unused = """
    ifeq (true,false)
    """
    
    # some python stuff
    print("Hello world")
    exit(1)
    
    unused = """
    endif
    
    # here comes make stuff
    .ONESHELL:
    .PHONY: all
    all:
        @/usr/bin/python $(lastword $(MAKEFILE_LIST))
        ec=$$?
        echo "script exitcode is $$ec"
        exit $$ec
    
    #"""
    

    也许更好的解决方案是简单地将
    python
    作为单个规则的自定义
    SHELL
    。虽然,在这种情况下,在同一条规则中混合python和shell脚本可能会很棘手(但我认为这不是真正必要的)。

    从源代码构建和安装更新的
    make
    是否切实可行?否。重点是为最终用户提供一个轻松的解决方案。管理创建临时文件更实用,因为除了要求它们运行
    sudo-apt-install-make
    之外,不需要任何更改。