Bash:「if」と「find」を一緒に使用して、フォルダ内のファイルを確認してください。

Bash:「if」と「find」を一緒に使用して、フォルダ内のファイルを確認してください。

一連の「histogram_0000_0000」フォルダを含む親フォルダがあります。すべてのフォルダで "out.txt"ファイルを検索し、フォルダ内のファイルが見つかるたびにそれを返すbashスクリプトを作成しようとしています(ファイルがすべてのフォルダにあることを確認するため)。私が得たスクリプトは次のとおりです。

#!/bin/bash
joblist='job_list.txt'
njobs=`wc ${joblist} | awk '{print $1}'`

cwd=`pwd`
for ((i=1 ; i <= ${njobs} ; i++ )); do
        folder=`awk '(NR=='${i}'){print}' ${joblist}`
        echo $folder
        cd ${folder}
        if [ find -name "out.txt" ]
        then
                echo out.txt found in $folder
        fi
        cd ${cwd}
done

しかし、実行するたびにエラーが発生します。

./checkrun.sh: 10行目: [: -name: バイナリ演算子が必要

周りを見回して「[[」と「]]」を使ってみましたが、なぜ運が良いのかわかりません!どんな助けでもいいでしょう。ありがとう、ジャック

答え1

[...]文字列または数値式をテストします。コマンドが一致することを確認するには、find出力(空でない文字列、を使用してテスト-n)を提供するかどうかをテストする必要があります。

if [[ -n "$(find -name 'out.txt')" ]]
then
    echo "out.txt found in $folder"
fi

$(...)コマンドの出力をキャプチャするために廃止された逆引用符の代わりに最新の構文を使用しています`...`

他の提案、

  • 行数を取得するnjobs=にはwc $ {joblist} | awk '{print $1}'``を簡素化できます。njobs=$(wc -l <"$joblist")

  • $iawk変数として渡されました。folder=$(awk -v i="$i" 'NR==i {print}' "$joblist}")

  • cdサブフォルダに移動してから、cd元の場所に戻らないでください。サブディレクトリを参照するには相対パスを使用し、制限されたcdコンテキストでサブディレクトリを維持するにはサブシェルを使用します。ここでは最初の方法を使用します。

      echo "$folder"
      if [[ -n "$(find "$folder" -name 'out.txt')" ]]
      then
          echo "out.txt found in $folder"
      fi
    
  • 常に相対パスの場合、パス$folderとして使用される場所ごとに「./$folder」と呼ばれます。これにより、-ダッシュ()で始まり、ダッシュ()を一連のオプションとして解釈するコマンドに混乱を招く可能性があります。

  • シェルにはbashすでに現在の作業ディレクトリの変数があるため、次cwd=`pwd`のように単純化できます。cwd="$PWD"

  • 使用https://shellcheck.net/コードを確認してください。 (プライベートコードの共有が心配な場合は、ローカルにインストールしてください。)

答え2

#!/bin/bash
joblist='job_list.txt'
njobs=`wc ${joblist} | awk '{print $1}'`

cwd=`pwd`
while IFS= read -r line
do
        folder="$line"   #`awk '(NR=='${i}'){print}' ${joblist}`
        echo $folder
        cd ${folder}
        if [ -f out.txt ]
        then
                echo out.txt found in $folder
        fi
        cd ${cwd}
done < job_list.txt

これが役に立つことを願っています。少し簡単です... line=current-line-from'job_list.txt' 1行ずつ読みますので、ファイルは次のようになります。

folder1
folder2
folder234

私の結果:

france1@macubuntu:/tmp/tmdf$ bash script.sh 
folder1
folder2
folder234
out.txt found in folder234
france1@macubuntu:/tmp/tmdf$ 

私が役立つことを願っています...

答え3

zsh代わりにこれを使用しますbash

#! /bin/zsh -
joblist='job_list.txt'
dirs=( ${(f)"$(<$joblist)"} )

for dir in $dirs; do
  first_out=( $dir/**/out.txt(NDY1) )
  if (( $#first_out )); then
    print -r out.txt found in $dir
  fi
done

bash他のGNUの場合はfind次のようになります。

#! /bin/bash -
joblist='job_list.txt'

dirs=(); readarray -t dirs < "$joblist"

for dir in "${dirs[@]}"; do
  [[ -n $dir ]] || continue
  [[ $dir = [/.]* ]] || dir=./$dir

  first_out=$(find "$dir" -name out.txt -print -quit)

  if [[ -n $first_out ]]; then
    printf '%s\n' "out.txt found in $dir"
  fi
done

いくつかの注意:

  • readarray -t lines < fileファイルの行を配列として保存することも可能ですが、開くことがfileできない場合は実行すらできず、設定もされませんので、事前に変数を初期化することが重要です。readarray$dirs
  • bash最後に、**/zshスタイルの再帰ワイルドカード()オプションのサポートが追加されましたglobstar。しかし、まだシンボリックリンク処理(バージョン間の動作の変更)に関連するいくつかの問題があり、さらに重要なのは、この場合、使用されたリストを並べ替えることなく、for、for、または最初の一致時に停止NなどnullglobDglobdotglob修飾子のサポートを追加しないないということです。Y1上。
  • findfind "$dir"で始まると$dir中断されます-。オプションfindの終わりの表示のサポートは実際にはサポートされていますが、で始まる引数はオプションでない場合(たとえば、または)、まだ述語として扱われるため、ここでは役に立ちません。だから絶対値ではなく、まだ始まっていないsを前に付けるのです(だからになります)。 BSDはこの問題の防止をサポートしていますが、GNUはまだサポートしていません。---()!./$dir.-my-annoying-dir-./-my-annoying-dir-findfind -f "$dir"find
  • 少なくとも1つが存在することを確認したい場合は、out.txtすべてを見つける必要はありません。最初のゲームで止めることができます。したがって(GNUによる)-quit(一部のBSDには-exitこれに関する規則があります)。
  • zshは${(f)"$(<file)"}改行に分割されますが、引用符がない場合は空の要素が削除されます(そうでない場合は、次の$dirs引用符がない次の要素はその要素を削除します)。空のパスは通常有効なパスではないため、エラーが発生する必要がありますが、接続すると、迷惑なことに/something有効である可能性のある無関係な絶対パスに変わります。前に来ると./現在のディレクトリになります。したがって、ここではスキップする方が良いです。したがって[[ -n $dir ]] || continue、bashバリアントです。

関連情報