bash 逐行读取文件时读取bash脚本中文件的最后一行
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15485555/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Read last line of file in bash script when reading file line by line
提问by PhiloEpisteme
I am writing a script to read commands from a file and execute a specific command. I want my script to work for either single input arguments or when an argument is a filename which contains the arguments in question.
我正在编写一个脚本来从文件中读取命令并执行特定的命令。我希望我的脚本适用于单个输入参数,或者当参数是包含相关参数的文件名时。
My code below works except for one problem, it ignores the last line of the file. So, if the file were as follows.
我下面的代码除了一个问题外都有效,它忽略了文件的最后一行。所以,如果文件如下。
file.txt
文件.txt
file1
file2
The script posted below only runs the command for file.txt
下面发布的脚本只运行 file.txt 的命令
for currentJob in "$@"
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
There is, of course, the obvious work around where after the while loop I repeat the steps for inside the loop to complete those commands with the last file, but this is not desirable as any changes I make inside the while loop must be repeated again outside of the while loop. I have searched around online and could not find anyone asking this precise question. I am sure it is out there, but I have not found it.
当然,有一个明显的解决方法是在 while 循环之后我重复循环内部的步骤以使用最后一个文件完成这些命令,但这不是可取的,因为我在 while 循环中所做的任何更改都必须再次重复在while循环之外。我在网上搜索过,找不到任何人问这个确切的问题。我确定它就在那里,但我还没有找到。
The output I get is as follows.
我得到的输出如下。
>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
My bash version is 3.2.48
我的 bash 版本是 3.2.48
回答by Gordon Davisson
It sounds like your input file is missing the newline character after its last line. When readencounters this, it sets the variable ($linein this case) to the last line, but then returns an end-of-file error so the loop doesn't execute for that last line. To work around this, you can make the loop execute if readsucceeds orit read anything into $line:
听起来您的输入文件在最后一行之后缺少换行符。当read遇到这种情况,将变量($line在这种情况下)到最后一行,但随后返回结束文件中的错误,从而循环不会对最后一行执行。要解决此问题,您可以使循环在read成功时执行或将任何内容读入$line:
...
while read line || [[ -n "$line" ]]; do
...
EDIT: the ||in the while condition is what's known as a short-circuit boolean -- it tries the first command (read line), and if that succeeds it skips the second ([[ -n "$line" ]]) and goes through the loop (basically, as long as the readsucceeds, it runs just like your original script). If the readfails, it checks the second command ([[ -n "$line" ]]) -- if readread anything into $linebefore hitting the end of file (i.e. if there was an unterminated last line in the file), this'll succeed, so the whilecondition as a whole is considered to have succeeded, and the loop runs one more time.
编辑:||while 条件是所谓的短路布尔值——它尝试第一个命令 ( read line),如果成功则跳过第二个 ( [[ -n "$line" ]]) 并通过循环(基本上,只要read成功,它就像您的原始脚本一样运行)。如果read失败,它会检查第二个命令 ( [[ -n "$line" ]]) -- 如果在到达文件末尾之前read读入任何内容$line(即,如果文件中的最后一行没有终止),这将成功,因此while会考虑整个条件成功了,循环再运行一次。
After that last unterminated line is processed, it'll run the test again. This time, the readwill fail (it's still at the end of file), and since readdidn't read anything into $linethis time the [[ -n "$line" ]]test will alsofail, so the whilecondition as a whole fails and the loop terminates.
在处理完最后一个未终止的行之后,它将再次运行测试。这一次,read将失败(它仍然在文件末尾),并且由于这次read没有读取任何内容$line,[[ -n "$line" ]]测试也将失败,因此整个while条件失败并且循环终止。
EDIT2: The [[ ]]is a bash conditional expression -- it's not a regular command, but it can be used in place of one. Its primary purpose is to succeed or fail, based on the condition inside it. In this case, the -ntest means succeed if the operand ("$line") is NONempty. There's a list of other test conditions here, as well as in the man page for the testcommand.
EDIT2:这[[ ]]是一个 bash 条件表达式——它不是一个常规命令,但它可以用来代替一个。它的主要目的是成功或失败,取决于它内部的条件。在这种情况下,-n如果操作数 ( "$line") 为非空,则测试意味着成功。此处以及该test命令的手册页中有其他测试条件的列表。
Note that a conditional expression in [[ ... ]]is subtly different from a test command [ ... ]-- see BashFAQ #031for differences and a list of available tests. And they're both different from an arithmetic expression with (( ... )), and completely different from a subshell with( ... )...
请注意,条件表达式 in[[ ... ]]与测试命令略有不同[ ... ]——有关差异和可用测试列表,请参阅BashFAQ #031。它们都不同于带有 的算术表达式(( ... )),也不同于带有( ... )...
回答by Majid Laissi
Your problem seems to be a missing carriage return in your file.
您的问题似乎是文件中缺少回车符。
If you cat your file, you need to see the last line successfully appearing before the promopt.
如果你 cat 你的文件,你需要看到最后一行成功出现在提示之前。
Otherwise try adding :
否则尝试添加:
echo "Reading "$currentJob
echo >> $currentJob #add new line
while read line; do
to force the last line of the file.
强制文件的最后一行。
回答by Jahid
Using grepwith while loop:
grep与 while 循环一起使用:
while IFS= read -r line; do
echo "$line"
done < <(grep "" file)
Using grep .instead of grep ""will skip the empty lines.
使用grep .而不是grep ""将跳过空行。
Note:
笔记:
Using
IFS=keeps any line indentation intact.
使用
IFS=可以保持任何行缩进完好无损。
回答by ling
I found some code that reads a file including the last line, and works without the [[ ]] command:
我发现了一些读取文件(包括最后一行)的代码,并且无需 [[ ]] 命令:
DONE=false
until $DONE; do
read s || DONE=true
# you code
done < FILE

