各ディレクトリに移動してコマンドを実行するにはどうすればよいですか?


143

どのように私はparent_directory内の各ディレクトリを通過し、bashスクリプト書くか実行コマンドを各ディレクトリを

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

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

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

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

回答:


108

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

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

(そして)、現在のディレクトリは、メインスクリプトで変更されていないので、サブシェルを作成します。


5
ワイルドカードは数字以外と一致しないため、ここでは問題になりませんが、一般的なケースでは、基本的には常にループ内のディレクトリ名を二重引用符で囲みます。 cd "$d"ワイルドカードが名前に空白やシェルのメタ文字を含むファイルと一致する状況に転送されるという点で優れています。
tripleee 2015

1
(ここでのすべての回答には同じ欠陥があるように見えますが、それはトップ投票された回答の中で最も重要です。)
tripleee '17

1
また、コマンドの大部分は、実際にどのディレクトリで実行するかを気にしません。 for f in foo bar; do cat "$f"/*.txt; done >output機能的にはと同等cat foo/*.txt bar/*.txt >outputです。ただし、ls引数を渡す方法に応じてわずかに異なる出力を生成する1つのコマンドです。同様に、相対ファイル名を出力するgrepまたはwcは、サブディレクトリから実行する場合は異なります(ただし、そのためにサブディレクトリに移動することは避けたい場合があります)。
tripleee 2015

158

トッドによって投稿されたこの回答は私を助けました。

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

\( ! -name . \) カレントディレクトリにあるコマンドを実行する避けることができます。


4
また、特定のフォルダーでのみコマンドを実行する場合:find FOLDER* -maxdepth 0 -type d \( ! -name . \) -exec bash -c "cd '{}' && pwd" \;
Martin K

3
-exec bash -c 'cd "$0" && pwd' {} \;一部のディレクトリには一重引用符と二重引用符が含まれていたため、私はやらなければなりませんでした。
Charlie Gorichanaz

12
追加することにより、現在のディレクトリを省略できます-mindepth 1
mdziob

これを関数に変更するには、pwd直接ではなく「git remote get-url origin」のようなコマンドを受け入れますか?
roachsinai

disd(){find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c 'cd "{}" && "$@"' \;}うまくいかない。
roachsinai

48

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からの要求に応じて)現在のディレクトリは無視されますが、名前がスペースで区切られます。

以下も参照してください。


1
find明示的なループを使用せずに配列の出力を配置する唯一の適切な方法は、Bash 4.4 withで使用できるようになりますmapfile -t -d '' dirs < <(find . -type d -print0)。それまでは、ループを使用する(または操作をに延期するfind)ことが唯一の選択肢です。
gniourf_gniourf

1
実際、dirs配列は実際には必要ありません。あなたは上のループ可能性findの出力(安全に)そうのように:find . -type d -print0 | while IFS= read -r -d '' file; do ...; done
gniourf_gniourf 2015年

@gniourf_gniourf私は視覚的であり、常にシンプルに見えるものを見つけ/作成しようとしています。たとえば、私はこのスクリプトを使用していて、bash配列を使用することで、(パイプを使用する代わりにロジックをより小さな部分に分離することにより)簡単で読みやすくなっています。追加のパイプを導入するとIFSread複雑さが増しているように見えます。私はそれについて考えなければなりません、多分それを行うより簡単な方法があるかもしれません。
kenorb

簡単に言うと、壊れているということであれば、はい、簡単な方法があります。心配する必要はありません。これらすべて、IFSおよびread(ご存知のとおり)慣れると第2の性質になります。これらは、スクリプトを作成する標準的で慣用的な方法の一部です。
gniourf_gniourf

ちなみに、最初のコマンドfind . -type d -execdir echo $(pwd)/{} ';'$(pwd)find
期待どおりに

29

これを実現するには、パイピングしてを使用しxargsます。問題-Iは、bashコマンドの部分文字列を、各によって渡された部分文字列に置き換えるフラグを使用する必要があることですxargs

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

pwd各ディレクトリで実行したいコマンドに置き換えることができます。


2
なぜこれが支持されなかったのかはわかりませんが、これまでに見つけた最も単純なスクリプトです。ありがとう
Linvi

20

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

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

$(PLAY AS MUCH AS YOU WANT)); 好きなだけコードを入れることができます。

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

乾杯、


3
インスタンスのカップルがあります「の無駄な使用lsここには-あなただけ行うことができますfor dir in $YOUR_TOP_LEVEL_FOLDER/*代わりに。
Mark Longair、2011

1
まあ、それは一般的な意味では役に立たないかもしれませんが、lsで直接フィルタリングを行うことができます(つまり、.tmpで終わるすべてのディレクトリ)。それが私がls $dir表現を使用した理由です
gforcada '19

13
for dir in PARENT/*
do
  test -d "$dir" || continue
  # Do something with $dir...
done

そして、これは非常に理解しやすいです!
Rbjz

6

1つのライナーは迅速で汚い使用法に適していますが、スクリプトを書くために以下のより詳細なバージョンを好みます。これは私が使用するテンプレートで、多くのエッジケースを処理し、より複雑なコードを記述してフォルダーで実行できます。関数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"

5

ファイルをフォーマットするだけでは要点がわかりません。フォルダを反復処理するだけなので...このようなものを探していますか?

cd parent
find . -type d | while read d; do
   ls $d/
done

4

あなたは使うことができます

find .

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

あなたはそのようにxargsコマンドで出力をパイプすることができますより

find . | xargs 'command here'

3
これは求められたものではありません。
kenorb 2015年

0
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

ディレクトリを再度バックアップするかcd、サブシェルで変更する必要があります。
Mark Longair、2011

反対票:編集が失われたcdため、このコードは実際には何も有用ではありません。
tripleee
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.