2012-08-28 54 views
3

我想寫一個bash腳本,可以處理參數和輸入類似於許多內置的bash命令。例如,像排序,它可以處理寫一個bash腳本接受來自所有可能方向的參數和輸入(類似於sort -k1 -r)最簡單的方法是什麼?

sort -k 1 -r input.txt 
sort input.txt -k 1 -r 
cat input.txt | sort -k 1 -r 
sort -k 1 -r < input.txt 
sort -k 1 -r <(cat input.txt) 

我想我的腳本能夠處理參數和輸入的類似的方式

myscript.sh -i 3 -b 4 input.txt 
myscript.sh input.txt -i 3 -b 4 
cat input.txt | myscript.sh -i 3 -b 4 
myscript.sh -i 3 -b 4 < input.txt 
myscript.sh -i 3 -b 4 <(cat input.txt) 

到目前爲止,我只用了一些功能「讀」和「getopts」,並認爲如果我自己嘗試這樣做可能會出現問題。

爲了讓我說出我的問題更清楚,讓input.text的內容是

aaa 
bbb 
ccc 

,我想用從參數值I和B做一些事情,但我只是把它打印出來在這個例子中。我想要的示例輸出是

i : 3 
b : 4 
aaa 
bbb 
ccc 

什麼是編寫代碼以處理我的上述示例命令以發出此輸出的最佳方式?

下面是從@chepner的三明治想法得到的代碼,這是目前爲止最好的。

#!/bin/bash -l 
die() { 
    echo >&2 "[exception] [email protected]" 
    exit 1 
} 

#parse param 
while getopts "i:b:" OPTION; do 
    case "$OPTION" in 
    i) 
     i="$OPTARG" 
     ;; 
    b) 
     b="$OPTARG" 
     ;; 
    *) 
     die "unrecognized option" 
     ;; 
    esac 
done 

if [ -e tmpfile ] 
then 
    rm tmpfile 
fi 

shift $(($OPTIND - 1)) 
echo "i : "$i 
echo "b : "$b 
cat $1 > tmpfile 

if read -t 0; then 
    cat >> tmpfile 
fi 

cat tmpfile 
+3

有什麼錯getopts的?谷歌,有很多例子。 –

+0

@KarolyHorvath我只是不知道如何使用getopts做到上面。 –

+1

getopts非常擅長解析參數,但我找不到任何使用getopts正確處理「進程替換」和「管道」的示例。 –

回答

6

執行摘要:您可以使用read -t 0來測試標準輸入是否有任何輸入可用。它將以標準輸入(通過管道或重定向文件)在狀態0數據立即可用時退出,如果不是,則數據爲1(例如,仍然連接到鍵盤)。然後,您可以根據是否需要從標準輸入讀取來分支腳本。

if read -t 0; then 
    # Do one thing 
else 
    # Do something else 
fi 

最棘手的部分,我在寫劇本,這樣它不會阻止閱讀標準輸入,如果你不用管什麼吧。

這似乎工作;改進歡迎。首先,消費標準輸入的所有內容;然後處理作爲參數給出的文件。

# The first call to read only succeeds when there is input 
# available on standard input. It does not actually consume 
# a line, though. 
if read -t 0; then 
    # Read standard input normally 
    while read line; do 
     echo $line 
    done 
fi 

# I'll assume you populate an array called input files 
# while processing your arguments 
for file in "${inputfiles[@]"; do 
    cat $file 
done 

這裏是圍繞sort一個毫無意義的包裝只是做演示相結合的其他輸入文件的標準輸入的另一種方式:

if read -t 0; then 
    cat | sort fileA fileB 
else 
    sort fileA file B 
fi 

一個更有用的命令可能是sandwich,其中輸出它的標準輸入(如果任何)在命令行上給出的兩個文件之間。

#!/bin/bash 

cat "$1" # Output the first file 
read -t 0 && cat # Pass through the standard input, if there is any 
cat "$2" # Output the second file 

# cat "$1" - "$2" is almost the same, but requires standard input. 

sandwich一些電話可能是

$ sandwich header.txt footer.txt 
$ sandwich header.txt footer.txt < body.txt 
$ cat chapter1.txt chapter2.txt | sandwich <(echo "My header") <(echo "My footer") 

這完全不是那麼回事,所以有改進的餘地......

$ cat - | sandwich header.txt footer.txt 
+0

你的代碼可以像「wc -l <​​(cat input)」一樣處理「進程替換」嗎? –

+0

是的。進程替換在您的腳本中顯示爲正常的文件名:'echo <(echo foo)'。不需要特殊處理; 'command1 <(command2)'是'command2> tmpfile的一種快捷方式; command1 tmpfile'。 – chepner

+0

所以你的建議是我需要分別處理管道和普通命令行的輸入?我希望可能有一套命令可以把這些東西包裝起來。 –

0
cat input.txt | command 
command < input.txt 
command <(cat input.txt) 

這三者是從應用程序觀點看是相同的,所述殼確實重定向。該應用程序只需要閱讀標準輸入。

command input.txt 
cat input.txt | command 

這些你處理文件中區別僅在於,在第一個它是input.txt,在第二個它的標準輸入,以便您可以使用-,大多數UNIX命令的支持它。

# echo "X" | cat - 
X 

所以你設置默認:filename=-,如果你讀了文件名選項,您覆蓋此變量。

+0

Thx爲您的答案。我知道這個概念和腳本必須能夠處理這個概念,但我不知道該怎麼做。我確實爲我的問題添加了一些解釋。我希望這會讓我的問題更清楚。 –

相關問題