2017-02-11 4 views
0

でファイルの名前を変更、私はフォルダ階層をフラット化しようとするが、内部のファイルとして、私はその前のフォルダ名とファイル名を拡張したい、同じ名前が付けられています。OSX端子:OSXのターミナルに階層

私は思いますここから取得したい:

/file1-dirA1-dirB1.ext 
/file1-dirA1-dirB2.ext 
... 
/file1-dirA2-dirB1.ext 
... 

/dirA1/dirB1/file1.ext 
/dirA1/dirB2/file1.ext 
... 
/dirA2/dirB1/file1.ext 
... 

私は(https://unix.stackexchange.com/questions/52814)平坦化して名前の変更(Batch renaming files in OSX terminal)を組み合わせることを試みていないが、まだ運ました...

私は "find"で始めるでしょうか?しかし、どのように "mv"にディレクトリ名を渡すことができますか?

ありがとうございます!

答えて

0

安全ではなく、非常に高速な方法は、このように、あなたが交換を実行するシェルコマンドに各ファイルを渡し、-execfindを使用するために、次のようになります。

(cd /path; find . -type f -exec sh -c 'newname=${1:2}; filename=${newname##*/}; dirname=${newname%/*}; newname=$filename-${dirname//\//-}; echo mv "$1" "$newname"' -- {} \;) 

cd /path理由の代わりに、 find /pathは、そのベースディレクトリからの相対パスで作業できるようにするため、フラットファイル名を簡単に作成できます。

要素のもう少し説明:

  • -exec sh -c '...' -- {}-c '...'で指定されたコマンドを実行し、shを実行します。 {}は、findで見つかるパスです。 -- ...の構文では、パラメータをスクリプトに位置引数として渡します。$1$2などでアクセスできます。
  • newname=${1:2}は、最初の位置引数である$1をとり、最初の2文字をスキップして、その部分文字列を抽出します。 find .の出力には./で始まるパスがあり、/-に置き換える前にそのパスを削除したいからです。
  • filename=${newname##*/}最後/
  • dirname=${newname%/*}はそれ
  • ${dirname//\//-}がすべて置き換えられた後、最後/、すべてを除去することで、パスのディレクトリ名の部分を抽出するまで、最初からすべてを除去することで、パスのファイル名部分を抽出し、出現頻度は/であり、-である。あなたは置き換えるのではなく/を削除したい場合は、それがファイル名に特殊文字で動作しますので、この技術は、安全である${dirname//\//}

を書くことができます。ファイルごとにshが実行されるため遅いです。

このステップの後、元のファイルの空のディレクトリが残り、あなたはおそらくそれらを削除する:

find /path -type d -empty -delete 
+0

ありがとうございます!できるだけ早く試みます。 - newname = $ {1:2}と新しい名前// \/- がそれぞれ正確に何をするかを教えてください(または教えてください)? – Frank

+0

私はより多くの説明を追加し、重要なタイプミスを修正しました。置き換えは、編集前と同じように、 'newname = $ {newname // \/- }'でなければならず、 'newname = $ {newname // \/- }'でなければなりません。 – janos

+0

ありがとう、ヤノス!実際には、元のファイル名の後ろにディレクトリ名を追加したいと思います。どのように私はmvにそれらを前置きするのではなく引数を追加するように指示しますか? (また、/文字を - に置き換えるのではなく、/文字を完全に削除するにはどうすればいいですか? "文字なし"と置き換えることはできません) – Frank

0

あなたが安全にwhile readfind … -print0出力を供給することによって、すべてのファイルに対してshを実行せずにこれを扱うことができますループのような:

while IFS= read -r -d '' old; do   # read filenames into $old 
              # -d '' : read until \0 
              # -r  : no backslash escapes 
              # IFS= : no trimming whitespace 
    if [[ $old =~ (.*)/(.*)\.(.*) ]]; then # regex with capture groups: 
     #   1 2  3 
     set -- "${BASH_REMATCH[@]}" 
     mv "$old" "${2}-${1//\/}.${3}" 
    fi 
done < <(find . -type f -print 0) 

上記set -- "${BASH_REMATCH[@]}"の目的は、正規表現一致を含む配列のメンバーを移動するだけです($1,など)に読みやすくするために使用します。