リストに基づいてファイルが存在することを確認します。

リストに基づいてファイルが存在することを確認します。

各行にデータファイルダウンロードコマンドを実行する「コマンド」テキストファイルがあります。コマンドファイルをbashに送信します。しかし、少数のダウンロードは失敗します。欠落している項目を見つけるために使用するアルゴリズムは次のとおりです。

  1. ダウンロード後にコマンドファイルに戻り、ダウンロードした各ファイルが存在することを確認します。
  2. ダウンロードがない場合は、コマンドラインを新しいコマンドファイルにコピーします。
  3. 残りのダウンロードのために新しいコマンドファイルを残しました。

以下は、アルゴリズムを実装するbashスクリプトです。

  1 #!/bin/bash
  2 while read line
  3 do
  4         for item in $line
  5         do
  6                 if [[ $item == *out_fname* ]]; then 
  7                         splitline=(${item//=/ })   
  8                         target_file=${splitline[1]}
  9                         if [ ! -f $target_file ]; then
 10                                 echo $line >> stillneed.txt
 11                         fi
 12                 fi
 13         done
 14 done < "$@"

Q:これはうまく機能しますが、より良いアルゴリズムや実装があります(おそらくbash以外のものを使用することもできます)。私がしたことは、人間がしなければならないことをbashに任せることだけでした。しかし、Unixは常に仕事を処理するより良い方法を持っているようです...

答え1

「out_fname」だけでなく、「out_fname=」を探しているようです。

私はawkとshellを混ぜて使用するか、Pythonを使用します。 awk/シェルから:

awk '{for(i=0;i<NF;i++) {if (index($i, 'out_fname=')) {split($i,A,/=/);print A[i]}}' "$@" |
    while read filename; do
        if [ ! -f $filename ]; then echo $filename; fi
    done > stillneed.txt

Pythonでは:

import fileinput, os
stillneed = open("stillneed.txt", "w")
for line in fileinput.input():
    for filename in [l.split('=')[1] for l in line.split() if l.find('out_fname=')!=-1]:
        if not os.path.exists(filename):
            print >>stillneed, filename

答え2

役に立つかどうかはわかりませんが、成功するまでコマンドを再試行する関数があります。

retry () {
    local delay=1 n

    if ! [[ $1 = *[^0-9]* ]]; then
        # TODO allow delay=0 (prevents Ctrl-C)
        if (($1 > 0)); then
            delay=${1:1}
        fi
        shift
    fi

    # run command
    while ! "$@"; do
        echo "retrying in ${delay}s"
        for ((n=delay; n>0; n--)); do
            sleep 1 || return
        done
    done
}; export -f retry

答え3

初期ダウンロードスクリプトの完了後に欠落しているコンテンツを確認するのではなく、ダウンロードスクリプトにいくつかのチェックを追加することをお勧めします。次の内容はテストせずにただ頭の中に書いています。

cat files_to_download|while read file; 
do
    SUCCESS="False"
    while [[ $SUCCESS == "False" ]];
    do
        wget $file;
        if [[ $? -eq 0 ]];
        then
            SUCCESS="True"
        fi
   done
done

答え4

echoその後、ファイルの各行を解析してファイル名を解決するよりも、ダウンロードが失敗した場合はその行をコピーすることをお勧めします。

[[ -f $1 ]] || { echo "$1 not found" >&2; exit 1; }
while read -r line; do
    $line || echo "$line" >> stillneed
done < "$1"

これはより効率的で、後で奇妙なファイル名(スペースを含む)について心配する必要はありません。

既存の方法を改善するには、標準パラメータ拡張を使用できます。

for f; do
    while read -r line; do
        for item in $line; do
            [[ $item = out_fname=* ]] || continue
            [[ -f ${item#out_fname=} ]] || echo "$line"
            break # assuming one fname per line
        done
    done < "$f"
done > stillneed

..しかし、何が起こるのか考えてみてください。out_fname='foo bar.ext'。また、イベントが発生した後に各行を確認しますが、コマンドの実行時にコマンドが有効であることを確認できることに注意してください。

stillneedループ全体を一度開くのがより効率的です。ダウンロードコマンドの出力を表示したい可能性が高いため、最初のコードスニペットではこれを行いませんでした。これはテストだけで外部コマンドは実行されないため、ファイルを一度開くことをお勧めします。 (使用すると>最初にファイルが切り捨てられます。私はfor f複数の入力ファイルを場所引数として受け入れました。必要に応じて上記と同じように追加するのは簡単です)。

私が強調すべき一つのことは引用ですecho "$line"echo $line一般的に言えば、引用はです。みんなフィールドを分割したい場合を除き、パラメータ拡張(変数を含む)です。

関連情報