无法使用 alpine os 在 docker 中使用 echo 配置代码,但在 ubuntu 中可以

Cannot configure code with echo in docker with alpine os but can in ubuntu

我有一个 Dockerfile,它最初是从 ubuntu 中提取的,我最近遇到了更轻量级的 alpine,所以想从中提取。我尝试构建的部分代码称为 Healpix which depends on cfitsio. When I originally built the ubuntu version I found this Dockerfile https://github.com/MilesCranmer/dockers/blob/master/dockerfiles/healpix.

本质上问题是以下在 ubuntu 中有效但在 alpine 中无效:

RUN echo "3\ngfortran\n\nY\n\n\ngcc\n\n\n\n\nN\n1\nY\nN\nN\n0\n" |
    ./configure && make

我得到的错误是

Something went wrong ...
Quitting configuration script !

./configure: exit: line 162: Illegal number: -1
The command '/bin/sh -c echo     "3\ngfortran\n\nY\n\n\ngcc\n\n\n\n\nN\n1\nY\nN\nN\n0\n" | ./configure     && make' returned a non-zero code: 2

有点令人困惑的是,所讨论的配置脚本不是 162 行长 https://sourceforge.net/p/healpix/code/HEAD/tree/branches/branch_v350r1006/configure。我已经尝试安装 bash 并将脚本更改为那个,但那没有用。

ubuntu Dockerfile

FROM ubuntu
RUN apt-get update && apt-get install -y gcc g++ gfortran make wget
WORKDIR /home
RUN wget \ 
   http://heasarc.gsfc.nasa.gov/FTP/software/fitsio/c/cfitsio_latest.tar.gz \
   && tar xzf cfitsio_latest.tar.gz
WORKDIR cfitsio
RUN ./configure --prefix=/usr && make && make install
WORKDIR /home
RUN wget \
   https://sourceforge.net/projects/healpix/files/Healpix_3.50/Healpix_3.50_2018Dec10.tar.gz \
   && tar xzf Healpix*.tar.gz
WORKDIR Healpix_3.50
RUN echo \
    "3\ngfortran\n\nY\n\n\ngcc\n\n\n\n\nN\n1\nY\nN\nN\n0\n" | ./configure \
    && make

高山 Dockerfile

FROM alpine
RUN apk --no-cache add gcc g++ gfortran make wget
WORKDIR /home
RUN wget \ 
   http://heasarc.gsfc.nasa.gov/FTP/software/fitsio/c/cfitsio_latest.tar.gz \
   && tar xzf cfitsio_latest.tar.gz
WORKDIR cfitsio
RUN ./configure --prefix=/usr && make && make install
WORKDIR /home
RUN wget \
   https://sourceforge.net/projects/healpix/files/Healpix_3.50/Healpix_3.50_2018Dec10.tar.gz \
   && tar xzf Healpix*.tar.gz
WORKDIR Healpix_3.50
RUN echo \
    "3\ngfortran\n\nY\n\n\ngcc\n\n\n\n\nN\n1\nY\nN\nN\n0\n" | ./configure \
    && make

TL;DR

在您的 Dockerfile 中,使用:

RUN /bin/echo -e "3\ngfortran\n[...]" | ./configure && make

在 Ubuntu 和 Alpine 上具有相同的行为。

解释

./configure 脚本使用 /bin/sh 执行(参见 shebang)。在 Ubuntu 上,/bin/sh 是 link 到 /bin/dash,而在 Alpine 上,/bin/sh 是 link 到 /bin/busybox

下面的小例子重现了您的问题。

考虑以下 ./configure 脚本:

#!/bin/sh

read -p "1st prompt : " first
read -p "2nd prompt : " second

echo "$first-$second"

在 Ubuntu 上:

docker run --rm -v $PWD/configure:/configure ubuntu:18.04 \
    /bin/sh -c 'echo "a\nb" | ./configure'

打印:

a-b

同时,在高山上:

docker run --rm -v $PWD/configure:/configure alpine:3.8 \
    /bin/sh -c 'echo "a\nb" | ./configure'

打印:

anb-

在 Alpine (busybox) 上,echoed 字符串 (a\nb) 被解释为单个参数,而在 Ubuntu (dash ), \n 用于分隔两个参数。

要在 Alpine 上获得与 Ubuntu 相同的行为,您可以 运行 :

docker run --rm -v $PWD/configure:/configure alpine:3.8 /bin/sh -c 'echo "a                   
b                                                 
" | ./configure'

或:

docker run --rm -v $PWD/configure:/configure alpine:3.8 /bin/sh -c \
    'echo -e "a\nb" | ./configure'

(见echo-e参数)

这 2 个命令打印:

a-b

至于你的Dockerfile,你应该这样写:

RUN /bin/echo -e "3\ngfortran\n[...]" | ./configure && make
使用

/bin/echo 而不是 echo 因为在 Ubuntu 上,echo -e "3\ngfortran\n[...]" 将打印 -e 3\nngfortran\n[...].

This is because echo is parsed a shell built-in, while /bin/echo is explicitly not (source : https://github.com/moby/moby/issues/8949#issuecomment-61682684).