2013-03-18 144 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