2009-11-12 231 views
14

Autoconf腳本遇到文件名或路徑名帶空格的問題。例如,帶空格的Shell變量,引用單個命令行選項

./configure CPPFLAGS="-I\"/path with space\"" 

結果(的config.log):

configure:3012: gcc -I"/path with space" conftest.c >&5 
gcc: with: No such file or directory 
gcc: space": No such file or directory 

從的./configure編譯命令是ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5',我不能修改這個(我也許可以,但各地工作以這種方式autoconf不是一個通用的解決方案)。

我認爲這歸結於獲取一個shell變量,其中包含空格作爲單個命令行變量進行分析,而不是在空間拆分。最簡單的外殼的例子我能想出是一個shell變量作爲自變量創建空間和嘗試列表中的文件與lsls

$ touch "a b" 
$ file="a b" 
$ ls $file 
ls: a: No such file or directory 
ls: b: No such file or directory 

這工作,但非法的,因爲在autoconf的我不能修改sh​​ell代碼:在引用的東西以下嘗試

$ ls "$file" 
a b 

無工作:

$ file="\"a \"b"; ls $file 
ls: "a: No such file or directory 
ls: b": No such file or directory 
$ file="a\ b" 
$ file="a\\ b" 
$ file="`echo \\"a b\\"`" 

等。

這是不可能在shell腳本中完成的嗎?是否有一個神奇的引用將使用空格將shell變量擴展爲單個命令行參數?

回答

8

您應該嘗試設置$IFS環境變量。

從人的bash(1):

IFS - 內部字段分隔符被膨脹之後和線與內置 命令所讀取的分割成單詞用於字分裂 。默認值是''space tab newline''。

例如

IFS=<C-v C-m> # newline 
file="a b" 
touch $file 
ls $file 

不要忘記設置$IFS背部或奇怪的事情會發生。

+5

我會將IFS設置爲空字符串;它也可以工作。 'saveIFS = 「$ IFS」; IFS = ''; ls $文件; IFS =「$ saveIFS」' – 2009-11-12 18:11:44

0

使用引號很有趣。從(輕輕地)閱讀bash手冊頁,我認爲你必須用\來逃避空間,因此「/帶空間的路徑」變成/路徑\空間我從來沒有試過引號,但它似乎沒有一般工作(你的例子)。逃避與ls一起工作,沒有引用和不改變IFS。

如果使用命令的「轉義空格」格式,會發生什麼?

+0

關鍵是使用'ls'作爲測試,而不是觸及它的論點。要求是能夠完全像這樣做'ls $ file',並且只對'file =「a b」'進行更改。這是將參數更改爲'configure'而不修改相關文件的類比。 – 2009-11-13 02:38:17

4

如果你給命令

gcc -I"x y z" 
在shell話,肯定是單個命令行參數

「-ixŸZ」將被傳遞給GCC。這是毫無疑問的。這就是雙引號的全部含義:雙引號內的內容不受字段拆分限制,因此也不受$ IFS限制。

但是你需要注意你需要的引號數量。舉例來說,如果你說

file="a b" # 1 

,然後你說

ls $file # 2 

什麼情況是,該文件變量的內容是「A B」,而不是「‘AB’」,因爲雙引號是當第1行被解析時,「吃掉」了。被替換的值然後被字段分隔開,並且在兩個文件'a'和'b'上獲得ls。得到你想要的東西的正確方法是

file="a b"; ls "$file" 

現在,在你原來的情況下,問題是,當你設置爲包含雙引號的字符串變量,雙引號後不會被解釋爲殼報價符號,但就像普通的字母一樣。這就是爲什麼當你做這樣的事情

file="\"a b\""; ls $file 

實際上殼的標記化文件變量的內容爲「「A」和「B」」當ls命令進行分析;雙引號不再是shell引用字符,而只是變量內容的一部分。這類似於如果你設置

file="\$HOME"; ls $file 

你會得到一個錯誤,'$ HOME'目錄不存在---沒有環境變量查找發生。

所以,你最好的選擇是

  1. 哈克的autoconf
  2. 不要使用空格路徑名(最佳解決方案)
1

你要引用整個說法,通過以下兩種方式:

./configure "CPPFLAGS=-I/path with space" 
./configure CPPFLAGS="-I/path with space" 

./configure命令然後看見單個argum ENT

"CPPFLAGS=-I/path with space" 

被解析爲具有值名爲«CPPFLAGS»參數«-I/path with space»(添加爲了清楚括號)

2

在Unix世界中的目錄名稱中使用空格只是要求麻煩。這不僅僅是shell腳本中的引用問題(無論如何都需要正確處理):有些工具根本無法處理文件名中的空格。例如,您不能(可移植地)編寫Makefile規則,該規則說明從「foo bar/baz.c」構建「baz.o」。

CPPFLAGS上述情況我會按優先順序排列:

  1. 修復系統無法使用任何使用空間,目錄名
  2. 寫周圍的編譯器小包裝,並呼籲./configure CC=mygcc。在這種情況下,mygcc可能是
     
    
    

    !/bin/sh

    gcc "-I/foo bar/include" "[email protected]"
  3. 創建符號鏈接(例如,/tmp/mypath),以可怕的路徑,並使用CPPFLAGS=-I/tmp/mypath
0
$ file="\"a b\"" 

$ eval ls $file 
+1

這不會解決問題,因爲autoconf腳本需要修改才能調用eval。問題的關鍵是避免做這種修改。 – 2012-10-11 10:20:41

0

一切都取決於變量是如何使用的。首先,請注意,如果您使用的是Autoconf,這可能意味着最終將使用make,因此規則由make規定,特別是默認的make規則。儘管您可能想要獨佔使用自己的規則,但工具之間必須保持一致,並且某些變量具有標準含義,因此您不希望偏離它們。這不是CPPFLAGS的情況,但這應該與標準的CFLAGS類似。請參閱POSIX make utility,其中變量只是簡單地用標準sh分詞擴展,該分詞不提供任何引用機制(字段分隔符由$IFS控制,但不要更改IFS變量以接受空格爲普通字符,因爲這會破壞其他內容,就像能夠以標準方式在這些變量中提供幾個-I和/或-L選項一樣)。

由於make有這樣的限制,我想在Autoconf中設法避免這個限制是沒有用的。

現在,由於空間必定是字段分隔符,唯一的可能是提供不含空格字符的路徑名。如果將來要支持路徑名中的空格,這可能會通過路徑名編碼完成,並在高級UI(有點像使用URL)進行解碼。或者,如果您有選擇並且真的想在路徑名中使用空格,則可以使用一些非ASCII空間(順便說一下,這是RISC OS如何通過強制它成爲不間斷空間來支持路徑名中的空間)。