シェルスクリプトは、すべてのサブディレクトリに対してシェルスクリプトを実行します。

シェルスクリプトは、すべてのサブディレクトリに対してシェルスクリプトを実行します。

日常的な作業を簡素化するためにスクリプトを作成しています。毎日会社サーバー内で何かを検索する必要があります。大丈夫です。しかし、今では各オブジェクトをサブディレクトリに分割しました。私は、既存のシェルスクリプトが特定のディレクトリ内のすべてのサブディレクトリで繰り返し実行されるソリューションを探しています。どうすればいいですか?私は初めてLinuxに触れ、まだ学んでいます。

これは私のスクリプトです。

#!/bin/bash
MainDir=/path/to/dir/containing/subdirs
# cd into dir
cd $MainDir

for dir in $(ls); do

#fetch start time of uut
grep -i "01_node_setup" $dir/his_file | tail -1 >> /home/xtee/sst-logs.out

#check if sysconfig.out exists
if [ -f $dir/sysconfig.out];
then
    grep -A 1 "Drive Model" $dir/sysconfig.out | tail -1 >> /home/xtee/sst-logs.out
else
    grep -m 1 "Pair0 DIMM0" $dir/node0/trans_file_prev/*setupsys* | tail -1 >> /home/xtee/sst-logs.out
fi

done

#cd back to where we started
cd $OLDPWD

良い人が私が台本を書くのを手伝ってくれました。ただし、binary file /some/subdirectory/grep出力の代わりにsst-logs.outファイルを表示することでうまく機能します。スクリプトにどのような問題がありますか?

答え1

検索で次の情報を入手できます。

find /your/dir/with/subdirs -type d -exec sh -c 'cd "{}" ; /path/to/your/script.sh ;' \;

答え2

スクリプトにはいくつかの問題があります。

cd $MainDir

これをお勧めしますcd "$MainDir"。重要ではありませんが、発展するのに良い習慣です。変数が引用符なしで拡張されると、変数の値が単語に分割され、各単語はシェルワイルドカードパターンとして扱われます。したがって、$MainDirスペースが含まれている\[?*場合やファイル名が一致する場合は、二重引用符を追加しても問題はありません。これらの追加の拡張を避けることができます。コマンド置換()の場合も同様です$(somecommand)変数とコマンドの置換には常に二重引用符を使用してください。分割とファイル名が一致したいかどうかわからない場合。

for dir in $(ls); do

出力を解析しません。lslsスクリプトでこれを使用する必要はほとんどありません。上記のように、コマンド置換の結果はワイルドカードパターンとして扱われる単語に分割されるため、印刷できない文字が壊れる可能性がある$(ls)だけでなくls、スペースやワイルドカードも壊れます。シェルには、ディレクトリにファイル名を一覧表示する機能が組み込まれています。

for dir in *; do

これにより、for dir in */; do現在のディレクトリのサブディレクトリのみが一致し、他の種類のファイルは一致しません。

if [ -f $dir/sysconfig.out];

();&|<>横の文字がシェル句読点である場合を除き、角括弧の両側にスペースが必要です。もう一度、変数置換の周りに二重引用符を入れます(これは変数置換がある他のすべての場所に適用されます)。if [ -f "$dir/sysconfig.out" ];

#cd back to where we started
cd $OLDPWD

これは役に立たない。プロセスが終了しようとしており、現在のディレクトリを変更しても影響はありません。各プロセスには独自のカレントディレクトリがあります。スクリプト内でこれを変更しても、スクリプトを呼び出すプログラムには影響しません。


質問された理由に戻って、欲しいものが何であるかは不明です。 " binary file /some/subdirectory/"はあまり意味がありません。ディレクトリと一緒にこのメッセージを受信できません。より良い助けを得るために、エラーメッセージをコピーして貼り付けてください。あなたはする必要があります常にコピー貼り付けエラーメッセージオンラインで助けを求めるとき。

あなたの説明によると、ファイルが1つのディレクトリより深いようです。その場合は、行を次のようfor dir in */; doに変更してください。

for dir in */*/; do

答え3

これを行う方法はいくつかあります。 forループで既存のスクリプトを実行したり、findとxargsを使用したり、grepの-r別名--recursiveオプションを使用したりすることもできます。

最も簡単な方法は、おそらく既存のスクリプトの周りにforループラッパーを書くことです。たとえば、

#! /bin/bash
cd /path/to/top/level/directory

for d in */ ; do 
  pushd $d
  # call your script here
  popd
done

答え4

find@rushの提案がわずかに改善され、スイッチを使用するのではなく、次の操作を実行するとコマンドの追加を回避できます。-execcd

find /path/to/dir/containing/subdirs -type d -execdir /path/to/your/script.sh \;

これにより、for元のスクリプトのループを完全に回避できます。

関連情報