web-dev-qa-db-ja.com

各ディレクトリに移動してコマンドを実行する方法は?

Parent_directory内の各ディレクトリとexecutes a command in each directoryを通過するbashスクリプトを記述する方法を教えてください。

ディレクトリ構造は次のとおりです。

parent_directory(名前は何でも構いません-パターンに従いません)

  • 001(ディレクトリ名はこのパターンに従います)
    • 0001.txt(ファイル名はこのパターンに従います)
    • 0002.txt
    • 0003.txt
  • 002
    • 0001.txt
    • 0002.txt
    • 0003.txt
    • 0004.txt
  • 003
    • 0001.txt

ディレクトリの数は不明です。

123
Van de Graff

現在のディレクトリがparent_directoryの場合、次のことができます。

for d in [0-9][0-9][0-9]
do
    ( cd "$d" && your-command-here )
done

(および)はサブシェルを作成するため、現在のディレクトリはメインスクリプトで変更されません。

94
Mark Longair

これは answer 投稿者 Todd に役立ちました。

find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c "cd '{}' && pwd" \;

\( ! -name . \)は、現在のディレクトリでコマンドを実行しないようにします。

138

GNU findを使用している場合は、-execdirパラメーターを試すことができます。例:

find . -type d -execdir realpath "{}" ';'

または( @ gniourf_gniourfコメント )に従って:

find . -type d -execdir sh -c 'printf "%s/%s\n" "$PWD" "$0"' {} \;

注:${0#./}の代わりに$0を使用して、前面の./を修正できます。

より実用的な例:

find . -name .git -type d -execdir git pull -v ';'

現在のディレクトリを含める場合は、-execを使用するとさらに簡単になります。

find . -type d -exec sh -c 'cd -P -- "{}" && pwd -P' \;

またはxargsを使用:

find . -type d -print0 | xargs -0 -L1 sh -c 'cd "$0" && pwd && echo Do stuff'

または @ gniourf_gniourf によって提案された同様の例:

find . -type d -print0 | while IFS= read -r -d '' file; do
# ...
done

上記の例は、名前にスペースを含むディレクトリをサポートしています。


または、bash配列に割り当てることにより:

dirs=($(find . -type d))
for dir in "${dirs[@]}"; do
  cd "$dir"
  echo $PWD
done

.を特定のフォルダー名に変更します。再帰的に実行する必要がない場合は、代わりにdirs=(*)を使用できます。上記の例では、名前にスペースが含まれるディレクトリはサポートされていません。

@ gniourf_gniourf が示唆するように、明示的なループを使用せずにfindの出力を配列に配置する唯一の適切な方法は、Bash 4.4で次のように使用できます。

mapfile -t -d '' dirs < <(find . -type d -print0)

または推奨方法ではありません( lsの解析

ls -d */ | awk '{print $NF}' | xargs -n1 sh -c 'cd $0 && pwd && echo Do stuff'

上記の例では、現在のディレクトリ(OPの要求どおり)は無視されますが、スペースを含む名前では中断されます。

こちらもご覧ください:

41
kenorb

トップレベルのフォルダーがわかっている場合は、次のように記述できます。

for dir in `ls $YOUR_TOP_LEVEL_FOLDER`;
do
    for subdir in `ls $YOUR_TOP_LEVEL_FOLDER/$dir`;
    do
      $(PLAY AS MUCH AS YOU WANT);
    done
done

$(好きなようにプレイ);必要なだけコードを配置できます。

どのディレクトリでも「cd」しなかったことに注意してください。

乾杯、

19
gforcada

これを実現するには、パイピングしてからxargsを使用します。問題は、bashコマンドのサブストリングを各xargsによって渡されるサブストリングに置き換える-Iフラグを使用する必要があることです。

ls -d */ | xargs -I {} bash -c "cd '{}' && pwd"

pwdを各ディレクトリで実行する任意のコマンドに置き換えることができます。

14
Piyush Singh
for dir in PARENT/*
do
  test -d "$dir" || continue
  # Do something with $dir...
done
10
Idelic

1つのライナーは迅速で汚れた使用に適していますが、以下ではスクリプトを記述するためのより冗長なバージョンを好みます。これは私が使用するテンプレートで、多くのEdgeのケースを処理し、フォルダーで実行するより複雑なコードを作成できます。関数dir_commandでbashコードを書くことができます。以下では、dir_coomandは、例としてgitの各リポジトリのタグ付けを実装しています。スクリプトの残りは、ディレクトリ内の各フォルダに対してdir_commandを呼び出します。特定のフォルダーセットのみを反復処理する例も含まれています。

#!/bin/bash

#Use set -x if you want to echo each command while getting executed
#set -x

#Save current directory so we can restore it later
cur=$PWD
#Save command line arguments so functions can access it
args=("$@")

#Put your code in this function
#To access command line arguments use syntax ${args[1]} etc
function dir_command {
    #This example command implements doing git status for folder
    cd $1
    echo "$(tput setaf 2)$1$(tput sgr 0)"
    git tag -a ${args[0]} -m "${args[1]}"
    git Push --tags
    cd ..
}

#This loop will go to each immediate child and execute dir_command
find . -maxdepth 1 -type d \( ! -name . \) | while read dir; do
   dir_command "$dir/"
done

#This example loop only loops through give set of folders    
declare -a dirs=("dir1" "dir2" "dir3")
for dir in "${dirs[@]}"; do
    dir_command "$dir/"
done

#Restore the folder
cd "$cur"
6
Shital Shah

使用できます

find .

現在のディレクトリのすべてのファイル/ディレクトリを再帰的に検索する

出力をパイプすることができるよりも、xargsコマンドのように

find . | xargs 'command here'
4
Dan Bizdadea

フォルダーを反復処理するだけなので、ファイルの書式設定でポイントを取得できません...このようなものを探していますか?

cd parent
find . -type d | while read d; do
   ls $d/
done
3
Aif
for p in [0-9][0-9][0-9];do
    (
        cd $p
        for f in [0-9][0-9][0-9][0-9]*.txt;do
            ls $f; # Your operands
        done
    )
done
0
Fedir RYKHTIK