10

ファイルからコマンドを読み取り、特定のコマンドを実行するスクリプトを作成しています。単一の入力引数に対して、または引数が問題の引数を含むファイル名である場合に、スクリプトを機能させたい。

以下の私のコードは、1つの問題を除いて機能し、ファイルの最後の行を無視します。したがって、ファイルが次の場合。

file.txt

file1
file2

以下に投稿されたスクリプトは、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

もちろん、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

4 に答える 4

25

入力ファイルの最後の行の後に改行文字がないようです。これreadに遭遇すると、変数($lineこの場合)を最後の行に設定しますが、ファイルの終わりエラーを返すため、その最後の行に対してループは実行されません。これを回避するには、read成功した場合にループを実行する、次のように何かを読み込みます$line

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

編集:||while条件は、短絡ブール値として知られているものです-最初のコマンド(read line)を試行し、それが成功すると、2番目の()をスキップしてループを通過します(基本的に、成功する[[ -n "$line" ]]限り、read元のスクリプトと同じように実行されます)。失敗した場合は、2番目のコマンド( )readをチェックします。ファイルの終わりに到達する前に何かを読み込んだ場合(つまり、ファイルに終了していない最後の行があった場合)、これは成功するため、全体としての状態が考慮されます。成功し、ループがもう一度実行されます。[[ -n "$line" ]]read$linewhile

最後の終了していない行が処理された後、テストが再度実行されます。今回readは失敗し(まだファイルの終わりにあります)、この時間にread何も読み込まなかったため、テスト失敗するため、条件全体が失敗し、ループが終了します。$line[[ -n "$line" ]]while

EDIT2:これ[[ ]]はbash条件式です。通常のコマンドではありませんが、代わりに使用できます。その主な目的は、内部の状態に基づいて成功または失敗することです。この場合、オペランド( )がNONemptyの場合、-nテスト手段は成功します。"$line"他のテスト条件のリストは、コマンドのマニュアルページと同様にここtestにあります。

の条件式は[[ ... ]]テストコマンドとは微妙に異なることに注意してください。違いと使用可能なテストのリストについては、BashFAQ#031[ ... ]を参照してください。そして、それらは両方とも、の算術式とは異なり、 ...のサブシェルとは完全に異なります。(( ... ))( ... )

于 2013-03-18T21:02:33.247 に答える
1

問題は、ファイルにキャリッジリターンがないことのようです。

ファイルをcatする場合は、promoptの前に最後の行が正常に表示されることを確認する必要があります。

それ以外の場合は、追加してみてください:

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

ファイルの最後の行を強制します。

于 2013-03-18T19:59:24.513 に答える
0

grepwhileループでの使用:

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

grep .の代わりに使用するgrep ""と、空の行がスキップされます。

ノート:

  1. を使用IFS=すると、行のインデントが損なわれません。

  2. ほとんどの場合、読み取りでは-rオプションを使用する必要があります。

于 2015-07-14T04:38:20.873 に答える
0

最後の行を含むファイルを読み取り、[[]]コマンドなしで機能するコードを見つけました。

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
于 2016-10-22T13:14:42.633 に答える