Чтение последней строки файла в скрипте bash при чтении файла строка за строкой

Я пишу сценарий для чтения команд из файла и выполнения определенной команды. Я хочу, чтобы мой скрипт работал либо для одного входного аргумента, либо когда аргумент является именем файла, содержащим рассматриваемые аргументы.

мой код ниже работает, за исключением одной проблемы, он игнорирует последнюю строку файла. Итак, если файл был следующим.

.txt
file1
file2

сценарий размещена ниже работает только команда файл.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

есть, конечно, очевидная работа вокруг того, где после цикла 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

4 ответов


похоже, что в вашем входном файле отсутствует символ новой строки после последней строки. Когда read встречи-это переменная ($line в этом случае) до последней строки, но затем возвращает ошибку конца файла, поэтому цикл не выполняется для этой последней строки. Чтобы обойти это, вы можете выполнить цикл, если read успешно или он читал что-нибудь в $line:

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

"правка":|| в то время как состояние, что известно как короткое замыкание boolean -- он пытается выполнить первую команду (read line), и если это удастся, он пропускает второй ([[ -n "$line" ]]) и проходит через цикл (в основном, до тех пор, пока read успешно, он работает так же, как ваш оригинальный скрипт). Если read не удается, он проверяет вторую команду ([[ -n "$line" ]]) -- if read читать ничего $line прежде чем попасть в конец файла (т. е. если в файле была unterminated последняя строка), это будет успешным, поэтому while условие в целом считается получилось, и петля проходит еще раз.

после последней незаконченной обработки, он снова выполните тест. На этот раз read произойдет сбой (он все еще находится в конце файла), и так как read ничего не читал в $line в этот раз .

обратите внимание, что условное выражение в [[ ... ]] тонко отличается от тестовой команды [ ... ] - см. BashFAQ #031 для различий и a список доступных тестов. И они оба отличаются от арифметического выражения с (( ... )), и полностью отличается от подуровень с( ... )...


ваша проблема, кажется, отсутствует возврат каретки в вашем файле.

Если вы cat ваш файл, вы должны увидеть последнюю строку успешно появляется перед promopt.

в противном случае попробуйте добавить :

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

в силу последней строке файла.


используя grep с циклом while:

while IFS= read -r line; do
  echo "$line"
done < <(grep "" file)

используя grep . вместо grep "" пропустит пустые строки.

Примечание:

  1. используя IFS= сохраняет любой отступ линии нетронутым.

  2. вы почти всегда должны использовать опцию-r с read.


Я нашел код, который читает файл, включая последнюю строку, и работает без команды [[]]:

http://www.unix.com/shell-programming-and-scripting/161645-read-file-using-while-loop-not-reading-last-line.html

DONE=false
until $DONE; do
    read s || DONE=true
    # you code
done < FILE