2013-05-31 94 views
0

這些行工作時,複製粘貼到外殼,但沒有在腳本工作:如何根據bash腳本中的命令行參數命名輸出文件?

ls -l file1 > /path/`echo !#:2`.txt 
ls -l file2 > /path/`echo !#:2`.txt 

ls -l file1 > /path/$(echo !#:2).txt 
ls -l file2 > /path/$(echo !#:2).txt 

什麼是在bash腳本這樣的語法?

如果可能,我想知道如何爲一個文件和文件夾中具有相同擴展名的所有文件執行此操作。

回答

3

非交互的shell有歷史擴展禁用。

以下兩行添加到您的腳本來啓用它:

set -o history 
set -o histexpand 
+0

謝謝。這實際上解決了我所有的問題。 – user2044638

1

(更新:我誤會了原來的問題是在腳本中提到的參數給腳本,不參數當前命令;這是一個改寫答案)

正如@choroba說,歷史是由禁用在腳本中是默認的,因爲它不是在腳本中這樣做的正確方法。

在腳本中做這樣的事情的首選方法是多次存儲在問題的項目(在此情況下,文件名)中的變量,然後參考它在命令:

fname=file1 
ls -l "$fname" > "/path/$fname.txt" 

請注意,如果包含空格或其他shell元字符,則應該幾乎總是將變量引用放在雙引號內(如上所述)以避免麻煩。如果您想爲多個文件做到這一點,使用for循環:

for fname in *; do # this will repeat for each file (or directory) in the current directory 
    ls -l "$fname" > "/path/$fname.txt" 
done 

如果你想在比當前目錄下的其它文件的某個地方運行,事情有點複雜。您可以使用/inputpath/*,但它會包含每個文件名的路徑(例如,它會使用「/ inputpath/file1」,「/ inputpath/file2」等運行循環),並且如果直接在輸出重定向你會得到像> /path/inputpath/file1.txt(即兩個不同的路徑將被附加在一起),可能不是你想要的東西。在這種情況下,你可以使用basename命令剝去不需要的路徑輸出的目的:

for fpath in /inputpath/*; do 
    ls -l "$fpath" > "/path/$(basename "$fpath").txt" 
done 

如果你想要的文件帶有特定擴展名的列表,只需使用*.foo/inputpath/*.foo適當。但是,在這種情況下,您將輸出到名爲例如「file1.foo.txt」;如果你不想堆疊擴展,basename有一個選項來裝飾件,以及:

for fpath in /inputpath/*.foo; do 
    ls -l "$fpath" > "/path/$(basename "$fpath" .foo).txt" 
done 

最後,它可能是整潔(根據實際操作的複雜程度,以及是否在腳本中多次出現)來包裝這一個功能,然後使用:

doStuffWithFile() { 
    ls -l "$1" > "/path/$(basename "$1" "$2").txt" 
} 

for fpath in /inputpath/*.foo; do 
    doStuffWithFile "$fpath" ".foo" 
done 
doStuffWithFile /otherpath/otherfile.bar .bar 
+0

嗯,那麼可能的誤解或我的Bash完全拙劣的版本。當我按照你所說的將輸出保存到'/ path/.txt'時。我想要的是在命令行參數後命名的每一行都有一個單獨的輸出文件,所以如果參數是'foo',我想要一個名爲'foo.txt'的輸出文件。如果第二個參數是'file2',我想要另一個名爲'file2.txt'的輸出文件。顯然,用'ls -l'來做這件事並沒有多大意義,我只是選擇它來證明我的請求,因爲解釋我實際需要的東西會有點複雜。 – user2044638