在子目录内递归移动文件

在子目录内递归移动文件
.
├── subdirectory-A
│   ├── 1.jpg
│   ├── 1.tif
│   ├── 2.jpg
│   ├── 2.tif
│   ├── JPEG
│   └── TIF
└── subdirectory-B
    ├── 1.jpg
    ├── 1.tif
    ├── 2.jpg
    ├── 2.tif
    ├── JPEG
    └── TIF

有人能帮忙吗?我正在尝试找到一种方法,通过在本地父目录中运行 shell 脚本中的 ( ) 将所有.tif文件移动到 TIF 目录,将所有.jpg文件移动到 JPEG 目录mv。我一直在使用

mv *.jpg JPEG/

在每个子目录中,但我需要在包含超过 17K 个目录的档案中执行此作业,并且一次一个目录的手动选项不是一个选项。

答案1

您可以rename使用bashglobstar选项来执行此操作:

shopt -s globstar
rename -n 's/.*\//$&JPEG\//' **/*.jpeg
rename -n 's/.*\//$&TIF\//' **/*.tif

-n选项让它只输出它将要做什么,删除它以实际执行移动。这里发生的事情是,由于匹配了任意数量的子目录,因此rename遍历任何子目录中的每个 eg文件。它用自身()后跟 替换其路径(直到最后一个 的所有内容) ,从而有效地将文件移动到此目录。.jpeg**/$&JPEG/

如果参数列表太长,上述命令将会抛出错误。使用此方法可以解决 shell 的ARG_MAX限制:

printf '%s\0' **/*.jpeg | xargs -0 rename -n 's/.*\//$&JPEG\//'
printf '%s\0' **/*.tif | xargs -0 rename -n 's/.*\//$&TIF\//'

这使用 shell 内置命令printf来构建一个零分隔的参数列表,该列表通过管道传输到具有最大参数数量的xargs调用。rename

示例运行

$ tree
.
├── subdirectory-A
│   ├── 1.jpeg
│   ├── 1.tif
│   ├── 2.jpeg
│   ├── 2.tif
│   ├── JPEG
│   └── TIF
└── subdirectory-B
    ├── 1.jpeg
    ├── 1.tif
    ├── 2.jpeg
    ├── 2.tif
    ├── JPEG
    └── TIF
$ shopt -s globstar
$ rename -n 's/.*\//$&JPEG\//' **/*.jpeg
rename(subdirectory-A/1.jpeg, subdirectory-A/JPEG/1.jpeg)
rename(subdirectory-A/2.jpeg, subdirectory-A/JPEG/2.jpeg)
rename(subdirectory-B/1.jpeg, subdirectory-B/JPEG/1.jpeg)
rename(subdirectory-B/2.jpeg, subdirectory-B/JPEG/2.jpeg)
$ rename 's/.*\//$&JPEG\//' **/*.jpeg
$ printf '%s\0' **/*.tif | xargs -0 rename 's/.*\//$&TIF\//'
$ tree
.
├── subdirectory-A
│   ├── JPEG
│   │   ├── 1.jpeg
│   │   └── 2.jpeg
│   └── TIF
│       ├── 1.tif
│       └── 2.tif
└── subdirectory-B
    ├── JPEG
    │   ├── 1.jpeg
    │   └── 2.jpeg
    └── TIF
        ├── 1.tif
        └── 2.tif

答案2

我首先想到的是以下 Bash 循环:

#!/bin/bash
for dir in */     # or use: subdirectory*/
do
    cd "$dir"
    mv *jpg JPG/
    mv *tif TIF/
    cd ..
done

作为内联命令使用的示例:

$ mkdir -p subdirectory-{A,B}/{TIF,JPG}; touch subdirectory-{A,B}/{1,2}.{jpg,tif}

$ for dir in */; do cd "$dir"; mv *jpg JPG/; mv *tif TIF/; cd ..; done

$ tree
.
├── subdirectory-A
│   ├── JPG
│   │   ├── 1.jpg
│   │   └── 2.jpg
│   └── TIF
│       ├── 1.tif
│       └── 2.tif
└── subdirectory-B
    ├── JPG
    │   ├── 1.jpg
    │   └── 2.jpg
    └── TIF
        ├── 1.tif
        └── 2.tif

6 directories, 8 files

相关问题:

答案3

既然您提到了“超过 17K 个目录”,findxargs就想到了。

# do this part Only Once  
cat >./TheScript <<"EOF"
#!/bin/bash
while $# -gt 0 ; do
    cd "$1"
    find . -maxdepth 1 -type f -name '*.jpg' -print | xargs --no-run-if-empty mv --target-directory=JPG
    find . -maxdepth 1 -type f -name '*.tif' -print | xargs --no-run-if-empty mv --target-directory=TIF
    cd "$OLDPWD"
    shift
done
exit 0
EOF
chmod +x ./TheScript
# end of "Only Once"


find . -type d \! -name 'JPG' -a \! -name 'TIF` -print |\
    xargs $PWD/.TheScript

相关内容