2016-10-10 5 views
0

Ich benutze Make Shell-Befehl, um einige Variablen zu füllen, und bei der Ausgabe wird angezeigt, dass sie auf die Werte gesetzt werden, die ich erwarte. Aber wenn ich sie an meine Rezepte übergebe, erscheinen sie alle leer. Ich vermute, dass make ein paar seltsame Parsing auf den Ergebnissen macht. ZB:Makefile Verwenden Sie Shell zum Erstellen von Variablen

MyTarget: $(MySources) 
    LINE='$(shell cat $< | grep GIMME_THE_LINE_I_WANT)' 
    CH9=$(shell echo $(LINE) | cut -b9) 
    echo $(CH9) # doesn't print anything 

ich mein Generator geprüft Befehle manuell durch SHELL=sh -XV Einstellung und wenn ich identische Befehle ausführen bekomme ich die richtigen Werte, es sieht aus wie bash Nullbewertung meine Variablen. Irgendeine Idee, was ist los?

+0

Gibt es irgendwelche Sonderzeichen in '$ (LINE)'? Sie sollten es z. 'Shell Echo '$ (LINE)' ' – Barmar

+0

Nebenbei bemerkt, dass [' cat' ist nutzlos] (http://www.iki.fi/era/unix/award.html) – tripleee

Antwort

5

Hier passiert einiges. Die erste ist, dass, wenn Sie haben:

MyTarget: $(MySources) 
    LINE='$(shell cat $< | grep GIMME_THE_LINE_I_WANT)' 

Sie sind ein LINE, kein make Variable namens Shell variable Einstellung. Die Build-Anweisungen für ein Ziel sind Shell-Befehle. Nach der ersten Zeile enthält die Shell-Variable $LINEGIMME_THE_LINE_I_WANT. Allerdings ...

... jeder Zeile in den Build-Anweisungen für ein Ziel läuft in einem separaten Shell-Prozess. Also, wenn Sie haben:

mytarget: 
    MYVAR=foo 
    echo $$MYVAR 

Sie keine Ausgabe sehen werden, weil $MYVAR wird im Rahmen des zweiten Befehls nicht gesetzt. Beachten Sie auch die Verwendung von $$ hier, denn sonst würde die $ von Make interpretiert werden (das heißt, Schreiben $MYVAR wäre eigentlich der Make-Ausdruck $M gefolgt von dem Text YVAR). Sie können dies beheben, indem logisch Ihre Linien zu einem einzigen Shell-Skript verbinden, wie folgt aus:

mytarget: 
    MYVAR=foo; \ 
    echo $$MYVAR 

Die \ ist Makefile-Syntax, die eine einzelne logische Zeile über mehrere physikalische Leitungen erstreckt, und natürlich ; einfach Shell ist Syntax für Kombinieren mehrerer Befehle in einer Zeile.

Mit all diesem Hintergrund konnten wir Ihr Ziel wie folgt umschreiben:

MyTarget: $(MySources) 
    LINE=$$(cat $< | grep GIMME_THE_LINE_I_WANT); \ 
    CH9=$$(echo $$LINE | cut -b9); \ 
    echo $$CH9 

Beachten Sie, dass da wir bereits ein Shell-Skript ausgeführt Ich bin nicht $(shell ...) Konstrukts ist verwenden und dass ich m Stellen Sie sicher, alle $ Zeichen zu entkommen, um sicherzustellen, dass die Shell, nicht Make, die variable Expansion behandelt.

Wenn Sie nur ein wenig weiter gehen, müssen Sie cat in diesem Skript nicht verwenden; schreiben Sie könnten einfach:

MyTarget: $(MySources) 
    LINE=$$(grep GIMME_THE_LINE_I_WANT $<); \ 
    CH9=$$(echo $$LINE | cut -b9); \ 
    echo $$CH9 

Oder:

MyTarget: $(MySources) 
    CH9=$$(grep GIMME_THE_LINE_I_WANT $< | cut -b9); \ 
    echo $$CH9 

(NB: Während nicht relevant zu dieser Lösung, es ist zwar bemerkenswert, dass jeder Aufruf von $(shell ...) auch in einem separaten Prozess ausgeführt wird, so dass ein Variable in einem gesetzt wird nicht in einem anderen verfügbar sein.)

-2

Die Marke führt jeden Befehl in seiner separaten Shell. Daher werden die Werte nicht übertragen.

Im Zweifelsfall können Sie es immer mit -d Option debuggen. Außerdem ist eine Debugging-Option sehr hilfreich, wenn Sie herausfinden möchten, warum eine Regel nicht wie beabsichtigt ausgelöst wurde.

~> cat Makefile 
MyTarget: 
     LINE="somevalue" 
     echo ${LINE} 
~> 
~> 
~> make -d MyTarget | tail -10 
LINE="somevalue" 
Putting child 0x2004fbb0 (MyTarget) PID 4052 on the chain. 
Live child 0x2004fbb0 (MyTarget) PID 4052 
Reaping winning child 0x2004fbb0 PID 4052 
echo 
Live child 0x2004fbb0 (MyTarget) PID 4192 

Reaping winning child 0x2004fbb0 PID 4192 
Removing child 0x2004fbb0 PID 4192 from chain. 
Successfully remade target file 'MyTarget'. 
~> 

Klärung Gerade für die Menschen, die Downvoted und bemerkte, dass meine obige Lösung nicht funktioniert: Erstens, die ich für meine Faulheit entschuldigen. Vielleicht hätte ich klar sein sollen. Lass mich es nochmal versuchen.

Das "make-d" ist keine Lösung für das Problem von OP.

Ich habe versucht, OP zu zeigen, wie er/sie debug Option verwenden könnte, um eine Vielzahl von Problemen zu lösen, die Menschen während der Verwendung von Makefiles begegnen (was, ich gebe zu, geht in einer kleinen Tangens als nur das OP-Problem zu lösen) .

Das obige Debug zeigt, dass der erste Befehl in einer Shell mit PID = 4052 ausgeführt wurde und der zweite Befehl in einer anderen Shell mit PID = 4192 ausgeführt wurde (die den Wert dieser Variablen nicht enthält). Es zeigt auch, dass die Verwendung einer Variable mit einem Dollar ($ {LINE}) nur ein Leerzeichen enthält (weil das Makefile es nicht als Shell-Variable interpretiert).

Nochmal um klar zu sein: "make -d" ist keine Lösung. Kombinieren Sie einfach die Befehle in einer Zeile, getrennt durch Kommas, verwenden Sie doppelte Dollar; Wenn die Zeile lang ist, entgehen Sie den neuen Zeilen.

MyTarget: 
     LINE="somevalue"; \ 
     echo $${LINE} 
+0

Dies wird nicht funktionieren, weil Wie Larsks bemerkt, wird der Ausdruck $ {LINE} 'durch Make ersetzt, nicht durch die Shell, und wird immer zu einem leeren Wert ausgewertet (selbst wenn Sie die beiden Befehle in derselben Shell ausführen). Sie können dies mit etwas so einfach wie 'LINE =" somevalue "versuchen; echo $ {LINE} '. –

Verwandte Themen