複数のディレクトリのファイルの並べ替えとコピー

複数のディレクトリのファイルの並べ替えとコピー

ファイルを含む複数のサブディレクトリがあるディレクトリがあります。

各ディレクトリのファイルを名前でアルファベット順に並べ替え、各ディレクトリの最初のファイルを指定された新しいディレクトリにコピーしたいと思います。

  • 隠しファイルを無視したいです。
  • ターゲットディレクトリに同じ名前のファイルがある場合は、両方のファイルを保存する必要があります。

サンプル:

parentdir
->dir1
    ->afile
    ->bfile
    ->cfile
->dir2
    ->dfile
    ->efile
    ->ffile
->dir3
    ->afile
    ->hfile
    ->ifile

次のように新しいディレクトリを入力するコマンドを実行したいと思います。

newdir
->afile
->afile.1
->dfile

これはどのように達成できますか?

答え1

最も簡単な方法は、コピー先を使用してlsファイルを一覧表示することです。headこのbashスクリプトに示されているように:

for d in ./*/; do
    src="$(ls "$d" | head -n 1)"
    dstbase="newdir/$(basename "$src")"
    if [[ ! -f "$dstbase" ]]; then
        cp "$src" "$dstbase"
    else
        suffix=1
        while [[ -f "$dstbase.$suffix" ]]; do
            let suffix++
        done
        cp "$src" "$dstbase.$suffix"
    fi
done

当然、それに応じてファイルパスを調整する必要があります。コピーするときなど、下のディレクトリを除外しようとするとdir1問題が発生する可能性があるため、これは非常に脆弱です。dir2また、未使用のファイル名を探すループに潜在的な競合状態があります。これはおそらく問題ではありませんが、複数のコピーを並列に実行するなどのことはしないでください。

答え2

これは次の行を使用して達成できます。

ls -ltr /parent_directory_path/ |
awk '$1~"^drw" {print $9}' |
while read line; do
  ls -l $line |
  awk '$1 ~ "^-r" {print $9}' |
  head -1 |
  awk -v line="$line" '{print "cp -rvfp"  "  " line"/"$1 " " "/newdir/" }';
done |
sh

答え3

zshGNUを使用するとcp

cd parentdir &&
  for dir (*(/)) (cp --backup=numbered -- $dir/*(.[1]) newdir/)

--backup=numberedファイル名が指定されたバックアップスキームを実装しましたfile.~1~file.~2~...したがって、最初のコピーが最後のコピーになりますfile.~max~(順序を置き換えるには、fileリストを逆に処理する代わりに*(/On))。*(/)

POSIXlyでは、次のことができます。

cp_numbered() (
  suffix=
  n=0
  while [ -e "$2$suffix" ] || [ -L "$2$suffix" ]; do
    suffix=.$((n += 1))
  done
  exec cp -- "$1" "$2$suffix"
)
cd parentdir &&
  for dir in */; do
    for file in "$dir"/*; do
      if [ -f "$file" ]; then
        cp_numbered "$file" "newdir/${file#*/}"
        continue 2
      fi
    done
  done

関連情報