[英]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.