对多个目录中的文件进行排序和复制

对多个目录中的文件进行排序和复制

我有一个包含几个子目录的目录,其中包含文件。

我想按名称字母顺序对每个目录中的文件进行排序,并将每个目录中的第一个文件复制到给定的新目录。

  • 我想忽略隐藏文件。
  • 如果目标目录中有同名文件,则两个文件都应保留。

样本:

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

我想运行一个命令来填充我的新目录,如下所示:

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

如何才能做到这一点?

答案1

我想最简单的方法是使用ls来列出文件,默认情况下它按字母顺序排列(并省略隐藏文件),使用 获取每个目录中的第一个文件head,然后使用一些 shell 代码来找出文件名它们应该被复制到。正如这个 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

相关内容