根据名称查找文件并同时移动它们并重命名

根据名称查找文件并同时移动它们并重命名

假设我有根据年份命名的目录,并根据主题代码包含 pdf 文件。

ls输出是:

$ ls -l
total 32
drwxrwxrwx 1 root root 4096 Apr  8 08:52 May-June-2011
drwxrwxrwx 1 root root 4096 Apr  8 08:52 Nov-Dec-2011
drwxrwxrwx 1 root root 4096 Apr  8 20:36 Summer-2012
drwxrwxrwx 1 root root 4096 Apr  8 08:52 Summer-2013
drwxrwxrwx 1 root root 4096 Apr  8 08:52 Summer-2014
drwxrwxrwx 1 root root 4096 Apr  8 08:52 Winter-2012
drwxrwxrwx 1 root root 4096 Apr  8 08:52 Winter-2013
drwxrwxrwx 1 root root 4096 Apr  8 08:52 Winter-2014

每个目录包含根据主题代码的 pdf 文件:-

ls -l May-June-2011/
total 808
-rwxrwxrwx 1 root root 104193 May  1  2011 161901.pdf
-rwxrwxrwx 1 root root 103380 May  1  2011 161902.pdf
-rwxrwxrwx 1 root root 115664 May  1  2011 161903.pdf
-rwxrwxrwx 1 root root  88953 May  1  2011 161904.pdf
-rwxrwxrwx 1 root root 179268 May  1  2011 161905.pdf
-rwxrwxrwx 1 root root 116158 May 24  2011 161906.pdf
-rwxrwxrwx 1 root root 106033 May  1  2011 161907.pdf

换句话说每个目录都有16190{1..7}.pdf


现在假设我想将所有内容(从提到的所有目录中)移动161901.pdf到特定目录(例如xyz),并重命名为其父文件夹的 name.pdf。

解释 :-

这是所有的列表161901.pdf

$ find -name 161901.pdf
./May-June-2011/161901.pdf
./Nov-Dec-2011/161901.pdf
./Summer-2012/161901.pdf
./Summer-2013/161901.pdf
./Summer-2014/161901.pdf
./Winter-2012/161901.pdf
./Winter-2013/161901.pdf
./Winter-2014/161901.pdf

我希望应该使用新名称(文件所在目录的名称)将其./May-June-2011/161901.pdf移入。即移动到xyzMay-June-2011.pdf./May-June-2011/161901.pdf./xyz/May-June-2011.pdf

类似./Nov-Dec-2011/161901.pdf./xyz/Nov-Dec-2011.pdf./Summer-2012/161901.pdf./xyz/Summer-2012.pdf等等(直到./Winter-2014/161901.pdf./xyz/Winter-2014.pdf)。

的预期输出ls xyz是:

$ls xyz
May-June-2011.pdf
Nov-Dec-2011.pdf
Summer-2012.pdf
Summer-2013.pdf
Summer-2014.pdf
Winter-2012.pdf
Winter-2013.pdf
Winter-2014.pdf

我怎样才能做到这一点? (如何find -exec或使用循环或其他)

答案1

Perl模块Unicode::争斗附带一个非常有用的脚本,名为改名(这很不幸,因为这个名称与 Linux 上的标准冲突rename(1))。有了它,你可以做这样的事情:

mkdir xyz
find . -name '*.pdf' -print0 | \
    rename -0 's!^\.!xyz!;  s!/[^/]*\.pdf$!.pdf!'

如果没有 Perl,您仍然可以使用一些 shell 管道来完成同样的事情:

mkdir xyz
find . -name '*.pdf' | sed 's/^/mv /' >src
find . -name '*.pdf' | sed 's!^\./!xyz/!; s!/[^/]*\.pdf$!.pdf!' >dest
join src dest | sh -
rm -f src dest

而且,我相信其他人会很快指出,您甚至可以使用<(...)进程替换将其放在一行上。但我不确定这会让事情变得更清晰。如今的计算机已经足够强大,可以使用更详细的语法。 ;)

答案2

find当您不需要递归地遍历目录树时,它很少有用。这里一个简单的循环和 shell 通配符就足够了。

for x in */161901.pdf; do
  mv -- "$x" "xyz/${x%/*}.pdf"
done

rename或者,在 Debian、Ubuntu 及其衍生产品上使用基于 Perl 的命令(prename在 Arch 上,而不是其他发行版上的 Linuxrename命令):

rename 's!/.*!!; $_="xyz/$_.pdf"' */161901.pdf

或者,使用 zsh:

autoload -U zmv
zmv '(*)/161901.pdf' 'xyz/$1.pdf'

答案3

一种方法是使用find -print文件列表并将其通过管道传输到awk您可以将其转换为您想要的任何内容的位置,例如cp命令:

$ find -name 161901.pdf -print | awk -v TARGET=xyz -F'/' '{ printf "cp %s %s/%s.pdf\n", $0, TARGET, $2; }'
cp ./May-June-2011/161901.pdf xyz/May-June-2011.pdf
cp ./Nov-Dec-2011/161901.pdf xyz/Nov-Dec-2011.pdf

然后可以将其通过管道传输到 shell 来执行:

find -name 161901.pdf -print | awk -v TARGET=xyz -F'/' '{ printf "cp %s %s/%s.pdf\n", $0, TARGET, $2; }' | sh 

答案4

如果你有重命名/改名命令

find -name 161901.pdf -exec prename -n 's!/!-!g; s!\W*!xyz/!' {} +

-n如果您喜欢所看到的内容,请删除。

(Larry Wall 和 Robin Barker 的名字与 perl.deb 包一起安装;Brian d FoyUnicode::Tussle重命名也可以)

相关内容