我花了将近一天半的时间来搜索这个问题,但没有找到答案。
我希望将该文件夹的名称添加为该.bin
文件夹中以 结尾的所有文件的前缀。
因此,如果文件夹的名称是,并且ABC
它包含文件aa.bin
、、bb.bin
等cc.bin
,那么我需要将它们重命名为ABC-aa.bin
、、等。ABC-bb.bin
ABC-cc.bin
此外,此文件夹ABC
还有子文件夹,我们称之为:ABC1
、、等,其中也包含文件。例如ABC2
,有、、等。ABC3
.bin
ABC1
aa1.bin
bb1.bin
cc1.bin
我需要该命令遍历所有文件夹并将该子文件夹的名称附加到其中的文件。因此,aa1.bin
将是ABC1-aa1.bin
,依此类推。
目录结构:
.
└── ABC
├── aa.bin
├── ABC1
│ ├── aa1.bin
│ └── bb1.bin
├── ABC2
│ ├── aa2.bin
│ └── bb2.bin
├── bb.bin
└── cc.bin
答案1
这是一个“单行”操作,使用 shell 内置命令来操作文件名:
find . -name '*.bin' -exec sh -c 'p="${1%/*}"; f="${1##*/}"; echo mv -- "$1" "$p/${p##*/}-$f"' sh {} \;
在目标目录中测试它,echo
如果结果看起来正确,则删除
例如
$ tree .
.
└── ABC
├── aa.bin
├── ABC1
│ ├── aa1.bin
│ └── bb1.bin
├── ABC2
│ ├── aa2.bin
│ └── bb2.bin
├── bb.bin
└── cc.bin
3 directories, 7 files
然后
$ find . -name '*.bin' -exec sh -c 'p="${1%/*}"; f="${1##*/}"; echo mv -- "$1" "$p/${p##*/}-$f"' sh {} \;
mv -- ./ABC/ABC2/bb2.bin ./ABC/ABC2/ABC2-bb2.bin
mv -- ./ABC/ABC2/aa2.bin ./ABC/ABC2/ABC2-aa2.bin
mv -- ./ABC/aa.bin ./ABC/ABC-aa.bin
mv -- ./ABC/bb.bin ./ABC/ABC-bb.bin
mv -- ./ABC/ABC1/bb1.bin ./ABC/ABC1/ABC1-bb1.bin
mv -- ./ABC/ABC1/aa1.bin ./ABC/ABC1/ABC1-aa1.bin
mv -- ./ABC/cc.bin ./ABC/ABC-cc.bin
看起来不错,因此删除echo
并再次运行
$ find . -name '*.bin' -exec sh -c 'p="${1%/*}"; f="${1##*/}"; mv -- "$1" "$p/${p##*/}-$f"' sh {} \;
给予
$ tree .
.
└── ABC
├── ABC1
│ ├── ABC1-aa1.bin
│ └── ABC1-bb1.bin
├── ABC2
│ ├── ABC2-aa2.bin
│ └── ABC2-bb2.bin
├── ABC-aa.bin
├── ABC-bb.bin
└── ABC-cc.bin
3 directories, 7 files
答案2
您可以使用find
、basename
和命令来执行此操作。例如,像在这个简单的脚本中dirname
:mv
#!/bin/bash
for f in $(find ABC -name '*.bin');
do
filename="$(basename $f)"
dir="$(dirname $f)"
lastdir="$(basename $dir)"
newname="$lastdir-$filename"
newpath="$dir/$newname"
mv $f $newpath
done
这里我使用 find 递归查找.bin
ABC 中的所有文件,然后遍历它们并提取最后一个文件夹名称。然后构造新路径并将文件移动到同一目录但使用新名称。
编辑:
为了执行此脚本,请将其内容复制到某个文件中。假设文件名为renameFiles.sh
。然后使其可执行:
chmod +x renameFiles.sh
此后,您可以使用 执行它./renameFiles.sh
。请注意,放置此文件的文件夹应与您的 ABC 文件夹所在的文件夹相同。
renameFiles.sh
ABC
aa.bin
bb.bin
ABC1
aa1.bin
etc.
答案3
使用rename
:
shopt -s globstar
rename -n '(! -f $_ || ! /.bin$/) && next; $" = "/"; my @f = split("/"); $f[@f-1] =~ s/^/$f[@f-2]-/; $_ = "@f"' **
shopt -s globstar
:如果设置,文件名扩展上下文中使用的模式“**”将匹配所有文件以及零个或多个目录和子目录。如果模式后跟“/”,则仅匹配目录和子目录。rename -n '! -f $_ && next; $" = "/"; my @f = split("/"); $f[@f-1] =~ s/^/$f[@f-2]-/; $_ = "@f"' **
:执行下列操作的试运行。对于通配符生成的每个文件名**
:如果文件不是常规文件或文件名不以 结尾.bin
,则跳至下一个文件名;将输出字段分隔符设置为/
;根据 拆分文件名/
;将倒数第二个字段添加到-
最后一个字段的前面;将新文件名分配给默认变量 ($_
)。
如果结果是预期的,请-n
从命令中删除该选项rename
。
$ tree
.
└── ABC
├── aa.bin
├── ABC1
│ ├── aa1.bin
│ └── bb1.bin
├── ABC2
│ ├── aa2.bin
│ └── bb2.bin
├── bb.bin
└── cc.bin
3 directories, 7 files
$ rename -n '(! -f $_ || ! /.bin$/) && next; $" = "/"; my @f = split("/"); $f[@f-1] =~ s/^/$f[@f-2]-/; $_ = "@f"' **
Exiting subroutine via next at (eval 4) line 1.
rename(ABC/aa.bin, ABC/ABC-aa.bin)
Exiting subroutine via next at (eval 4) line 1.
rename(ABC/ABC1/aa1.bin, ABC/ABC1/ABC1-aa1.bin)
rename(ABC/ABC1/bb1.bin, ABC/ABC1/ABC1-bb1.bin)
Exiting subroutine via next at (eval 4) line 1.
rename(ABC/ABC2/aa2.bin, ABC/ABC2/ABC2-aa2.bin)
rename(ABC/ABC2/bb2.bin, ABC/ABC2/ABC2-bb2.bin)
rename(ABC/bb.bin, ABC/ABC-bb.bin)
rename(ABC/cc.bin, ABC/ABC-cc.bin)