awkを使用して.txtドキュメントに10000のパスを完成させ、ファイルが存在することを確認してください...?

awkを使用して.txtドキュメントに10000のパスを完成させ、ファイルが存在することを確認してください...?

私の写真ライブラリのすべてのファイルを読み、実際に存在することを確認したいと思います。これまでのところ、私のAppleScriptの知識はこれを行うのに十分です。ただし、これには多くのファイルが含まれており、AppleScriptはこれには適していません。 10,000ファイルには20分かかります。そのため、スクリプトの最も重要な部分を実行するためにシェルスクリプトを使用することにしました。しかし、私はUnixの世界の経験がなかったので、インターネット検索に関する2日間の集中講座を履修しなければなりませんでした。 しかし今、私はあなたの助けが必要なポイントに達しました!

私の実験は次のとおりです。

AppleScriptにすべて含めます。編集するファイルが多いので、各ステップの間に一時テキストファイルとして保存しておくのが最善のようです。最初のステップはデータベースを読み取ることです。たった1秒しかかからない:

パス|名前|ID|参照|外付けハードドライブ名

2018/03/27/20180327-122110/TVTower.JPG|TVTower|hA3CRRfPSS6FXqk7IDobLw|0|
Projekte/BCT 2017/BCT Fotos GPS/BCT_GPS_001.JPG|BCT_A_GPS_001|hyvsQgiaR4e3ou7XIZ%Gjg|1|Media
Leo/Carmina Burana/Leo UdK/IMG_0626.JPG|IMG_0626|j7342DtGSmag7YVLN1Nzhg|1|Logic
Users/spazek/Desktop/WeTransfer/Bild 2.png|Bild 2|Sa7rckZiSd2bIiRVO0JidA|1|macOS

次の手順では、欠落しているパス部分を追加します。

/Users/spazek/Pictures/Fotos Library.photoslibrary/Masters/2018/03/27/20180327-122110/TVTower.JPG|TVTower|hA3CRRfPSS6FXqk7IDobLw|0|
/Volumes/Logic/Projekte/BCT 2017/BCT Fotos GPS/BCT_GPS_001.JPG|BCT_A_GPS_001|hyvsQgiaR4e3ou7XIZ%Gjg|1|Media
/Volumes/Logic/Leo/Carmina Burana/Leo UdK/IMG_0626.JPG|IMG_0626|j7342DtGSmag7YVLN1Nzhg|1|Logic
/Users/spazek/Desktop/WeTransfer/Bild 2.png|Bild 2|Sa7rckZiSd2bIiRVO0JidA|1|macOS

私のソリューションは、Macで10,000個のファイルを処理するのに2分30分かかります。実行中のAppleScriptが過負荷制限に達したようです! Terminal.appで実行すると、ウィンドウのタイトルでawkとbashの間に常にジャンプがあることがわかります。何か間違っているようです。

次のステップでは、パスが存在することを確認したいと思います。前のスクリプトと似ているので、時間も長くかかります。最後のステップは、欠落しているファイルをテキストファイルに書き込むことです。

sqlite3  -separator $'|' /Users/spazek/Desktop/xsystx/systphotos.db 'select RKMaster.imagePath, RKMaster.name, RKMaster.uuid, RKMaster.fileIsReference, ( select RKVolume.name from RKVolume where RKVolume.modelId  = RKMaster.volumeId) from RKMaster' > /Users/spazek/Desktop/filelist1.txt

while read f; do
    var1=`echo "$f" | awk -F[=\|] '{print $1}'`;
    var2=`echo "$f" | awk -F[=\|] '{print $2}'` ;
    var3=`echo "$f" | awk -F[=\|] '{print $3}'` ;
    var4=`echo "$f" | awk -F[=\|] '{print $4}'` ;
    var5=`echo "$f" | awk -F[=\|] '{print $5}'` ;
    if  [ "$var4" == 0 ] ; then
        echo /Users/spazek/Pictures/Fotos Library.photoslibrary/Masters/"${f}" ;
    else
        if [ "$var5" == "macOS" ]; then
            echo /"${f}" ;
        else
            echo /Volumes/"$var5"/"${f}";
        fi;
    fi >> /Users/spazek/Desktop/filelist2.txt;
done < /Users/spazek/Desktop/filelist1.txt

while read f; do
    var1=`echo "$f" | awk -F[=\|] '{print $1}'`;
    var3=`echo "$f" | awk -F[=\|] '{print $3}'` ;
    test -f "$var1" || echo "$var1|$var3" >> /Users/spazek/Desktop/filelist3.txt;
done < /Users/spazek/Desktop/filelist2.txt

while read f; do
    var1=`echo "$f" | awk -F[=\|] '{print $1}'`;
    var2=`echo "$f" | awk -F[=\|] '{print $2}'` ;
    test -f "$var1" || echo "Name = $var2 \n Path = $var1 \n";
done > ~/Desktop/Photos_MissingItems.txt < /Users/spazek/Desktop/filelist3.txt

スクリプトを改善するための助けや提案を受けたいです。

ベストアンサー1

awkGNUバージョン4以降がインストールされている場合は、標準のawkまたはGNUアドバンストバージョンにはない機能を提供する外部モジュールをロードできますawkfilefuncsこのfilefuncsモジュールには、ファイルに関する情報(存在するかどうかを含む)を取得するために使用できるシステム機能のラッパーが含まれていawkますstat

次のawkスクリプトはfilefuncsモジュールをロードし、各入力行を読み取り、5番目の列を調べて各入力ファイル名の前のパスを確認し、ファイルが存在することを確認します。その場合は、フルパスとファイル名を標準出力として印刷します。それ以外の場合は、stderrに警告メッセージを印刷します。

連想配列paths(別名「ハッシュ」または「ハッシュ配列」)とデフォルトのプリセットパスは、ユーザーが意図したものに最適な推測です.必要に応じて調整してください。あなたのコメントの1つで述べたものではなく、あなたが提供した例のデータと一致します(Media-> / Volumes / Logicの明らかなエラーがあっても)。あなたのコメントが正しい場合は、コードが簡素化される可能性があります。

#!/usr/bin/awk -f

# this will only work with GNU awk >= version 4.0
@load "filefuncs"

BEGIN {
  FS=OFS="|";
  paths["default"] = "/Users/spazek/Pictures/Fotos Library.photoslibrary/Masters/";
  paths["Logic"] = "/Volumes/Logic/";
  paths["Media"] = "/Volumes/Logic/";
  paths["macOS"] = "/";
}

{ if ($5 in paths) {
    filename = paths[$5] $1;
  } else { # $5 not known in paths array, use a default
    filename = paths["default"] $1;
  }

  # try to stat the file. get the return code in variable 'rc' and error
  # string (if any) in 'error'.
  rc=stat(filename,fstat);
  error=ERRNO;   # oddly, ERRNO is a string, not a number.

  if (rc == -1) {  # return code of -1 is "No such file or directory"
    # print warning to stdout and skip to next input line
    print filename ": " error > "/dev/stderr"
    next;
  };

  # filename exists, do something with filename.
  print filename, $2, $3, $4, $5;
}

たとえば、別の名前で保存して./exists.awk実行可能にしchmod +x(シェルスクリプトを使用するのと同じ)、次のように実行します。

./exists.awk /Users/spazek/Desktop/filelist1.txt

または、sqlite3を直接パイプで接続します。

sqlite3  -separator $'|' /Users/spazek/Desktop/xsystx/systphotos.db \
'select RKMaster.imagePath, RKMaster.name, RKMaster.uuid, RKMaster.fileIsReference, ( select RKVolume.name from RKVolume where RKVolume.modelId  = RKMaster.volumeId) from RKMaster' \
  | ./exists.awk

awk現在、Mac OSにどのバージョンが提供されているかわかりません。私はBSDやFree Software FoundationがGPLv3ライセンスに移行する前のGNUの古代バージョンかもしれないと思いますawk(これがMacが現在のバージョン4ではなく古代v3に付いている理由です。これはAppleによるものではありません)。awkbashbashできないbashをアップグレードしてください。に慣れる。使用醸造より高いバージョンのGNUが必要な場合、bashまたはawk)。

とにかく、GNU awk> = v4.0がインストールされていない場合は、すべてのバージョンのperl.

次のperlスクリプトは非標準のPerlモジュールや機能を使用せず、Perlにはperlファイルの存在をテストするためのstat()同様の演算子があるため、組み込み関数の使用も必要ありません。ここでは、次のようにファイルが存在するかどうかをテストするために演算子を使用しshます。-esh

#!/usr/bin/perl

use strict;

# declare %paths hash
my %paths = (
  "default" => "/Users/spazek/Pictures/Fotos Library.photoslibrary/Masters/",
  "Media"   => "/Volumes/Logic/",
  "Logic"   => "/Volumes/Logic/",
  "macOS"   => "/",
);

# main loop, read in each line of input and process it.
while(<>) {
  chomp; # strip trailing linefeed from end-of-line
  my $filename='';  # declare $filename to belong to this scope

  # split input on "|" characters
  my ($path,$name,$id,$reference,$diskname) = split /\|/;

  if (defined($paths{$diskname})) {
    $filename = $paths{$diskname} . $path;
  } else {  # diskname not known in %paths hash, use a default
    $filename = paths{"default"} . $path;
  }

  if (! -e $filename) {
    # print warning to stderr and skip to next input line
    warn "$filename: No such file or directory\n";
    next;
  };

  # filename exists, do something with filename.
  print join('|', $filename, $id, $reference, $diskname), "\n";
}

別の名前で保存exists.plして実行可能にしますchmod +x。次に実行:

./exists.pl /Users/spazek/Desktop/filelist1.txt

while readこれらのスクリプトの1つは、同様のループを使用するシェルスクリプトよりも数百または数千倍高速です。

おすすめ記事