2012-10-02 65 views
4

我希望我的bash腳本檢查運行目錄的名稱。喜歡的東西:shell腳本:檢查目錄名並將其轉換爲小寫

#!/bin/bash 

path=eval 'pwd' 

dirname=eval 'basename $path' 

但它不工作:我得到

./foo.sh: line 5: basename $path: command not found 

我怎樣才能解決呢?此外,一旦我得到dirname包含正確的dirname,我想將其轉換爲小寫,以測試它。我可以在awk的命令行上執行此操作:

echo $dirname | awk '{print tolower($0)}' 

但是我如何將返回值捕獲到變量中?謝謝你在前進,

問候

塞爾吉奧

回答

3

爲什麼不使用:

#!/bin/bash 

path=`pwd` 
dirname=`basename $path | awk '{print tolower($0)}'` 

或者,如果你想這樣做,作爲一個班輪:

dirname=`pwd | xargs basename | awk '{print tolower($0)}'` 
+0

謝謝!很棒。不幸的是,我的鍵盤沒有正確的刻度:(幸運的是,我能夠複製並粘貼您的代碼在我的腳本中。 – DeltaIV

+0

@DeltaIV好聽的!我想你總是可以輸入ALT-96來獲得它:-) – Benj

+1

使用'$(pwd)'代替反引號。它們更容易嵌套,比反引號更明顯。另外,你的鍵盤上有這些鍵:) – chepner

0
B=$(echo "Some text that has CAPITAL letters " | awk '{print tolower($0)}') 
2

你可以改寫它到

dirname=eval "basename $path" 

使用單引號,您不會獲得shell擴展,但您想要擴展$path

BTW:我suggesst使用

path=$(basename $path) 

,如果你這樣做

path=$(basename $(pwd)) 

或獲得小寫結果的方式更通用的和更好的可讀性

path=$(basename $(pwd) | awk '{print tolower($0)}') 

path=$(basename $(pwd) | tr 'A-Z' 'a-z') 
+0

用'tr'最後一個建議+1。我會用'tr [:upper:] [:lower:]' – mouviciel

+0

'dirname = eval「basename $ path」'不起作用,但其他的都是完美的。謝謝! – DeltaIV

0

eval執行傳遞給它的命令,但它只返回命令退出狀態碼,所以你不能真正在set操作符中使用它。要走的路嵌入命令到集合運算符要麼使用權單引號或$()

所以腳本將是這樣的:

#!/bin/bash 

curr_path=$(pwd) 
echo $curr_path 
curr_dir=$(basename $curr_path) 
echo $curr_dir 
echo $curr_dir | awk '{print tolower($0)}' 
2

形式

x=y cmd 

意味着臨時設置環境變量x至值y,然後運行cmd,這是如何解釋這些行:

path=eval 'pwd' 
dirname=eval 'basename $path' 

也就是說,他們沒有按照你所期望的那樣做,而是將環境變量設置爲文字值eval,然後運行(或未能找到)命令。正如其他人所說的,將命令結果內插到字符串中的方法是將其放入$(...)(首選)或`...`(傳統)。而且,一般來說,用雙引號包裝它們會更安全(因爲將所有內插引用包裹在引號中更安全)。

path="$(pwd)" 
dirname="$(basename "$path")" 

(從技術上說,在這種情況下,外引號不是必須的。但是,我會說這仍然是一個好習慣。)

0

您的代碼不工作,因爲你用單引號而不是雙引號。單引號會阻止可變擴展,因此$path不會擴展到您要使用的路徑,並且會照原樣使用,因爲它如果是字符串。

您的awk調用也不會出於同樣的原因。

雖然可以解決這個問題用雙引號代替單引號,像這樣:

#!/bin/bash 

path=eval "pwd" 
dirname=eval "basename $path" 

我會建議使用重音符,而不是(在這種情況下). There's no reason to use eval`另外,你也可以用它來收集返回值,你感興趣的是:

#!/bin/bash 

path=`pwd` 
dirname=`basename $path` 
variable=`echo $dirname | awk "{print tolower($0)}"` 
+0

您的第一個代碼示例將不起作用。 (詳情請參閱我的回答。) – danfuzz

+0

正確!謝謝 :-) –

0

下面是從我的答案What platform independent way to find directory of shell executable in shell script?摘錄其中,本身完全回答你的問題除了小寫的一部分,這在我看來,已經正式地址在這裏的其他答案許多次。

什麼是我的唯一答案是,當我試圖把它寫的其他問題,我遇到了你確切的問題 - 我怎麼了函數的結果存儲在一個變量?好吧,你可以看到,有一些幫助,我想出了一個非常簡單,非常強大的解決方案:

我可以通過功能的排序信使變量和反引用任何明確的使用所產生的函數的參數中的$1根據需要命名爲eval,並且在函數例程完成時,我使用eval和反斜槓引用技巧爲我的信使變量賦予我想要的值,而無需知道它的名稱。

在充分披露,儘管這是解決我的問題,這是任何手段我的解決方案我以前曾經有幾次去過那裏,但他的一些描述雖然可能很精彩,但還是有些超出我的聯盟,所以我認爲如果在前一段中包含我自己的版本, 。雖然當然,一旦我明白了,理解起來很簡單,因爲特別是這一點,我不得不長時間思考,弄清楚它是如何工作的。無論如何,你可以在Rich's sh tricks處找到這個以及更多,我也在自己的答案的摘錄下摘錄了他的頁面的相關部分。

... 摘錄: ...

雖然沒有嚴格的POSIX的是,realpath是2012年以來一個GNU核心應用。全面披露:在我注意到它在info coreutils TOC中並且立即想到[鏈接的]問題之前從未聽說過,但是使用以下函數作爲證明應該可靠(很快POSIXLY?),並且我希望能夠有效地提供它來電者有絕對貨源$0

% _abs_0() { 
> o1="${1%%/*}"; ${o1:="${1}"}; ${o1:=`realpath "${1}"`}; eval "$1=\${o1}"; 
> } 
% _abs_0 ${abs0:="${0}"} ; printf %s\\n "${abs0}" 
/no/more/dots/in/your/path2.sh 

編輯:這可能是值得強調的是這個解決方案使用POSIX parameter expansion首先檢查是否路徑實際需要擴大,並試圖這樣做之前解決的。這應該通過信使可變返回一個絕對來源$0(與顯着的例外,它會保留symlinks有效因爲我能想象它可以做的路線是否已經是絕對的。 ...

小修改:在文檔中找到realpath之前,我已經至少縮減了我的版本的[版本下方]不依賴於時間領域,因爲它在不第一ps命令],但是,公平的警告,測試一些後,我不太相信ps在其命令路徑擴展容量

在另一方面完全可靠,你可以這樣做:

ps ww -fp $$ | grep -Eo '/[^:]*'"${0#*/}" 

eval "abs0=${`ps ww -fp $$ | grep -Eo ' /'`#?}" 

... 而從Rich's sh tricks ...

從一個shell函數返回一個字符串

正如從命令替換上述缺陷可以看出,stdout是不是一個好途徑shell函數將字符串返回給它們的調用者,除非輸出格式爲尾隨換行符不重要。當然,這種做法對於處理任意字符串的函數是不可接受的。那麼,可以做些什麼?

試試這個:

func() { 
body here 
eval "$1=\${foo}" 
} 

當然${foo}中可以通過任何一種替代的替代。這裏的關鍵技巧是評估線和轉義的使用。當eval的參數由主命令解析器構造時,「$1」被展開。但「${foo}」在此階段未擴展,因爲「$」已被引用。相反,它在eval評估其參數時展開。如果還不清楚爲什麼這很重要,請考慮以下怎麼會不好:

foo='hello ; rm -rf /' 
dest=bar 
eval "$dest=$foo" 

但當然,下面的版本是完全安全的:

foo='hello ; rm -rf /' 
dest=bar 
eval "$dest=\$foo" 

注意的是,在最初的例子,「$1」是用於允許調用者傳遞目標變量名稱作爲函數的參數。如果您的函數需要使用shift命令,例如將其餘參數作爲[email protected]來處理,那麼在函數的開頭將「$1」的值保存在一個臨時變量中可能會很有用。