2013-03-18 140 views
9

我正在編寫腳本以從文件讀取命令並執行特定命令。我希望我的腳本能夠處理單個輸入參數,或者當參數是包含參數的文件名時。在逐行讀取文件時讀取bash腳本中文件的最後一行

我的代碼如下工作,除了一個問題,它忽略了文件的最後一行。所以,如果文件如下。

file.txt的

file1 
file2 

下面貼只運行該腳本file.txt的命令

for currentJob in "[email protected]" 
do 
    if [[ "$currentJob" != *.* ]] #single file input arg 
    then 
     echo $currentJob 
     serverJobName="$(tr '[A-Z]' '[a-z]' <<< "$currentJob")" #Change to lowercase 
                    #run cURL job 
     curl -o "$currentJob"PisaInterfaces.xml http://www.ebi.ac.uk/msd-srv/pisa/cgi-bin/interfaces.pisa?"$serverJobName" 
    else #file with list of pdbs 
     echo "Reading "$currentJob 
     while read line; do 
      echo "-"$line 
      serverJobName="$(tr '[A-Z]' '[a-z]' <<< "$line")" 
      curl -o "$line"PisaInterfaces.xml http://www.ebi.ac.uk/msd-srv/pisa/cgi-bin/interfaces.pisa?"$serverJobName" 
     done < "$currentJob" 
    fi 
done 

有,當然,顯而易見的解決辦法,其中while循環後,我再說一遍循環內部的步驟用最後一個文件來完成這些命令,但這是不可取的,因爲我在while循環中做的任何更改都必須在while循環之外重複。我已經在網上搜索,找不到任何人提出這個確切的問題。我確定它在那裏,但我沒有找到它。

我得到的輸出如下。

>testScript.sh file.txt 
Reading file.txt 
-file1 
    % Total % Received % Xferd Average Speed Time Time  Time Current 
           Dload Upload Total Spent Left Speed 
100 642k 0 642k 0  0 349k  0 --:--:-- 0:00:01 --:--:-- 492k 

我的bash的版本是3.2.48

回答

24

聽起來你的輸入文件在最後一行之後缺少換行符。當read遇到這種情況時,它將變量(本例中爲$line)設置爲最後一行,但隨後返回文件結束錯誤,因此不會爲最後一行執行循環。要解決這個問題,可以使循環執行,如果read成功它讀任何東西到$line

... 
while read line || [[ -n "$line" ]]; do 
    ... 

編輯:在while條件||是什麼所謂的短路布爾 - 它嘗試第一個命令(read line),如果成功則跳過第二個([[ -n "$line" ]])並遍歷循環(基本上,只要read成功,它就像原始腳本一樣運行)。如果read失敗,它會檢查第二個命令([[ -n "$line" ]]) - 如果read在碰到文件結尾之前(即,如果文件中存在未終止的最後一行)讀取任何內容到$line,這將成功,因此while條件作爲一個整體被認爲是成功的,循環再運行一次。

之後,處理最後一個未終止的行,它將再次運行測試。這一次,read將失敗(它仍然在文件的結尾),由於read沒有讀任何東西到$line此時[[ -n "$line" ]]測試將失敗,所以while條件作爲一個整體失敗,循環終止。

編輯2:[[ ]]是bash條件表達式 - 它不是一個常規命令,但它可以用來代替一個。其主要目的是根據內部條件成功或失敗。在這種情況下,如果操作數("$line")爲NONempty,則-n測試方法成功。還有其他測試條件列表here以及test命令的手冊頁。

請注意,[[ ... ]]中的條件表達式與測試命令[ ... ]略有不同 - 請參閱BashFAQ #031以瞭解差異和可用測試的列表。而且他們從一個算術表達式都用不同((...)),並從(...)子shell完全不同......

+1

您的建議奏效,謝謝。根據你的回答,似乎在每次迭代結束時,$ line被設置爲下一行讀取的下一個值,然後它檢查是否有更多的行要用「read line」參數讀取。 [[-n「$ line」]]檢查$ line是否爲空?它是否正確。你介意第二學期的語法究竟是什麼意思? – PhiloEpisteme 2013-03-19 05:07:49

+1

感謝您的描述。我意識到邏輯的結構和||的含義跡象。我知道C++,但我不熟悉-n命令。它是否僅僅意味着「是空的」? – PhiloEpisteme 2013-03-19 18:15:31

1

你的問題似乎是在您的文件缺少回車。

如果您捕捉了您的文件,您需要看到最後一行成功出現在promopt之前。

否則嘗試添加:

echo "Reading "$currentJob 
    echo >> $currentJob #add new line 
    while read line; do 

強制文件的最後一行。

+0

此解決方案工作以及。但是,它不會導致包含回車符的輸入文件出現問題嗎? – PhiloEpisteme 2013-03-19 05:10:16

+0

您可以檢查您使用的行是否爲空 – 2013-03-19 11:05:36

+0

我使用以下行來解決此問題。如果[[「$ line」!= * [a-zA-Z0-9] *]]這不是檢查一個空行,但它有訣竅。你建議更好的解決方案嗎? – PhiloEpisteme 2013-03-19 18:14:26