簡體   English   中英

shell腳本:檢查目錄名稱並轉換為小寫

[英]shell script: check directory name and convert to lowercase

我希望我的bash腳本檢查運行它的目錄的名稱。 就像是:

#!/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)}'

但是如何將返回值捕獲到變量中? 先感謝您,

最好的祝福

塞爾吉奧

為什么不使用:

#!/bin/bash

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

或者如果你想把它作為一個班輪:

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

你可以重寫它

dirname=eval "basename $path"

使用單引號,您不會獲得shell擴展,但是您希望擴展$path

順便說一句:我建議用

path=$(basename $path)

如果你這樣做,它會更通用,更易讀

path=$(basename $(pwd))

或獲得小寫結果

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

要么

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

表格

x=y cmd

意味着暫時將環境變量x設置為值y ,然后運行cmd ,這是解釋這些行的方式:

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

也就是說,它們並沒有完全按照您的期望進行操作,而是將環境變量設置為文字值eval ,然后運行(或無法找到)命令。 正如其他人所說的那樣,將命令結果插入字符串的方法是將其放在$(...) (首選)或`...` (遺留)中。 並且,作為一般規則,用雙引號將它們包裝起來更安全(因為在引號中包裝任何插值引用更安全)。

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

(從技術上講,在這種情況下,外部引號並不是絕對必要的。但是,我認為它仍然是一個好習慣。)

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

eval執行傳遞給它的命令,但它只返回命令退出狀態代碼,因此你無法在set運算符中真正使用它。 將命令嵌入到set運算符中以使用正確的單引號或$()

所以腳本看起來像這樣:

#!/bin/bash

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

您的代碼不起作用,因為您使用單引號而不是雙引號。 單引號可以防止變量擴展,因此$path不會擴展到您想要使用的路徑中,而是按原樣使用,因為它是一個字符串。

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

雖然你可以解決用雙引號替換單引號的問題,如下所示:

#!/bin/bash

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

我建議改用嚴重的口音( ). There's no reason to use 在這種情況下). There's no reason to use eval`。 另外,您還可以使用它來收集您感興趣的返回值:

#!/bin/bash

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

以下是我對在shell腳本中查找shell可執行文件目錄的獨立平台方式的回答的摘錄 除了小寫部分之外,它本身完全回答了你的問題,在我看來,這個問題在其他答案中得到了很好的解決。

我的答案有什么獨特之處在於,當我試圖為另一個問題編寫它時,我遇到了您的確切問題 - 如何將函數的結果存儲在變量中? 好吧,正如你所看到的,在一些幫助下,我找到了一個非常簡單且非常強大的解決方案:

我可以傳遞函數一個messenger變量並取消引用任意顯式使用結果函數的參數$1名稱和必要的eval ,並且在函數例程完成時,我使用eval和一個反斜杠引用技巧來為我的messenger變量賦值我希望不必知道它的名字。

在完全披露中,雖然這是我的問題的解決方案但它絕不我的解決方案。 我曾經有好幾次去過那里,但是他的一些描述雖然可能很精彩,但是我的聯盟還有一些,所以我認為如果在前一段中包含我自己的版本,其他人可能會受益。 雖然我一旦理解這一點非常簡單,特別是對於這一點,我不得不長時間地思考它是如何工作的。 無論如何,你可以在Rich的伎倆中找到更多內容,我也在我自己的答案摘錄下摘錄了他的頁面的相關部分。

...... EXCERPT: ......

雖然不是嚴格的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參數擴展來首先檢查路徑是否實際需要在嘗試之前進行擴展和解析。 這應返回的絕對來源$0通過信使變量 (與顯着的例外,它會保留symlinks盡可能有效地我能想象這是可以做到的路線是否已經是絕對的。 ...

次要編輯 :在文檔中找到realpath之前,我至少減少了我的[以下版本]的版本,不依賴於時間字段[就像在第一個ps命令中那樣],但是,公平警告,在測試之后一些我不太相信ps在命令路徑擴展能力方面是完全可靠的

另一方面,你可以這樣做:

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

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

...... 還有Rich的伎倆 ......

從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命令,例如將剩余的參數作為“$@” ,那么在函數開頭的臨時變量中保存“$1”的值可能很有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM