web-dev-qa-db-ja.com

GNUスペースを含むファイル名を処理することはできますか?

私はいくつかのファイルを含むディレクトリを持っていますが、そのいくつかは名前にスペースがあります:

_Test workspace/
Another directory/
file1.ext
file2.ext
demo 2012-03-23.odp
_

このディレクトリでGNUの$(wildcard)コマンドを使用し、$(foreach)を使用して結果を反復処理し、すべてを出力します。コードは次のとおりです。

_FOO := $(wildcard *)
$(info FOO = $(FOO))
$(foreach PLACE,$(FOO),$(info PLACE = $(PLACE)))
_

これが印刷されると予想されるものです。

_Test workspace
Another directory
file1.ext
file2.ext
demo 2012-03-23.odp
_

私が実際に得るものは次のとおりです。

_Test
workspace
Another
directory
file1.ext
file2.ext
demo
2012-03-23.odp
_

後者は明らかに私には役に立たない。 documentation for $(wildcard) flat-outは、「スペースで区切られた名前のリスト」を返すが、これが引き起こす大きな問題を完全に認識できないことを示しています。 $(foreach)の-​​ documentation もありません。

これを回避することは可能ですか?もしそうなら、どのように?スペースを削除するためにすべてのファイルとディレクトリの名前を変更することはオプションではありません。

67
qntm

バグ #712 は、スペースを含む名前をmakeが処理しないことを示唆しています。どこにも、決して。

部分的に実装されていると言っているブログ投稿 をスペースをエスケープして_\_(_\\_はタイプミスまたはフォーマットアーティファクトのようです)が見つかりましたが、

  • $(wildcard)以外の関数では機能しません。
  • 特殊変数_$?_、_$^_、_$+_およびユーザー定義変数を含む変数から名前のリストを展開する場合は機能しません。つまり、$(wildcard)は正しいファイルと一致しますが、結果を解釈することはできません。

したがって、明示的または非常に単純なパターンルールを使用すると、それを機能させることができますが、それを超えると運が悪くなります。スペースをサポートする他のビルドシステムを探す必要があります。 jam // bjam が、 sconswafantnant および msbuild すべてが機能するはずです。

49
Jan Hudec

GNU Makeは、スペースで区切られたファイル名では非常に不十分です。

スペースは、Wordリストで区切り文字として使用されます。

このブログ投稿 は状況をうまく要約していますが、警告:\ではなく\\を誤って使用しています

target: some\ file some\ other\ file

some\ file some\ other\ file:
    echo done

変数を使用することもできますので、これも動作します

VAR := some\ file some\ other\ file

target: $(VAR)

$(VAR):
    echo done

wildcard関数のみがエスケープを認識します。そのため、多くの苦痛を伴わない凝った操作はできません。


しかし、シェルが区切り文字としてスペースを使用することも忘れないでください

echo donetouch $@に変更したい場合、スラッシュを追加してシェル用にエスケープする必要があります。

VAR := some\ file

target: $(VAR)

$(VAR):
    touch $(subst \,\\,$@)

または、おそらく引用符を使用します

VAR := some\ file some\ other\ file

target: $(VAR)

$(VAR):
    touch '$@'

結局、多くの苦痛を避けたい場合は、GNU= makeとシェルの両方で、ファイル名にスペースを入れないでください。 Makeで十分です。

18
Paul Draper

この方法では、$?などのリストされたファイル名と、ファイルのリストであるユーザー変数も使用できます。

Makeでスペースを処理する最良の方法は、スペースを他の文字に置き換えることです。

s+ = $(subst \ ,+,$1)

+s = $(subst +,\ ,$1)

$(call s+,foo bar): $(call s+,bar baz) $(call s+,bar\ baz2)
    # Will also shows list of dependencies with spaces.  
    @echo Making $(call +s,$@) from $(call +s,$?)

$(call s+,bar\ baz):

    @echo Making $(call +s,$@)

$(call s+,bar\ baz2):

    @echo Making $(call +s,$@)

出力

Making bar baz
Making bar baz2
Making foo bar from bar baz bar baz2

すべてのGNU Make関数を使用して、ファイル名のリストを安全に操作できます。これらの名前をルールで使用する前に、必ず+を削除してください。

SRCS := a\ b.c c\ d.c e\ f.c

SRCS := $(call s+,$(SRCS))

# Can manipulate list with substituted spaces
OBJS := $(SRCS:.c=.o)

# Rule that has object files as dependencies.
exampleRule:$(call +s,$(OBJS))
    # You can now use the list of OBJS (spaces are converted back).
    @echo Object files: $(call +s,$(OBJS))

a\ b.o:
    # a b.o rule commands go here...
    @echo in rule: a b.o

c\ d.o:

e\ f.o:

出力

in rule: a b.o
Object files: a b.o c d.o e f.o

この情報はすべて、他の全員が投稿していた blog からのものです。

ほとんどの人は、パスにスペースを使用しないか、Windows 8.3パスを使用することを推奨しているように見えますが、スペースを使用する必要がある場合は、スペースをエスケープして置換を行います。

13
Mr_Moneybags

シェルにもう少し依存する場合は、これにより、スペースを含む名前を適切に保持できるリストが表示されます。

$(Shell find | sed 's: :\\ :g')
4
benzaita

元の質問は「名前の変更はオプションではない」と言っていましたが、多くのコメント者は、名前の変更がMakeがスペースを処理できる唯一の方法であると指摘しました。中間の方法をお勧めします。Makeを使用して一時的にファイルの名前を変更してから、元の名前に戻します。これにより、Makeのすべての機能が暗黙のルールやその他の利点とともに提供されますが、ファイルの命名スキームが混乱することはありません。

# Make cannot handle spaces in filenames, so temporarily rename them
nospaces:
    rename -v 's/ /%20/g' *\ *
# After Make is done, rename files back to having spaces
yesspaces:
    rename -v 's/%20/ /g' *%20*

これらのターゲットは、make nospacesおよびmake yesspacesを使用して手動で呼び出すことも、それらに依存する他のターゲットを持つこともできます。たとえば、サーバーとファイルを同期する前に、ファイル名にスペースを戻す「プッシュ」ターゲットが必要な場合があります。

# Put spaces back in filenames before uploading
Push: yesspaces
    git Push

[サイドノート:+ss+を使用することを提案する答えを試しましたが、Makefileの読み取りとデバッグが難しくなりました。 :%.wav : %.ogg ; oggdec "$<"。]

1
hackerb9

他の答えはすでに問題をうまくカバーしています。 \-エスケープが依存関係でも機能することを示すための例を作成しました。

$ make --version
GNU Make 4.0
Built for x86_64-pc-linux-gnu
Copyright (C) 1988-2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ sed 's/^  /\t/' >Makefile <<'_EOF_'
X = $(Shell find -name 'x*' -type f | sed 's/ /\\ /g')
all: $(X)
  head $(X)
_EOF_
$ touch 'x 1'
$ touch 'x 2'
$ make
head ./x\ 2 ./x\ 1
==> ./x 2 <==

==> ./x 1 <==
$
0
Kirill Bulygin