我有一个包含许多.png
文件的文件夹,例如:
Jeff Smith 1.png
Jeff Donald 1.png
Jeff Donald 2.png
Jeff Smith 2.png
Jeff Roberts.png
Kyle Reds.png
Kyle Reds 1.png
Kyle Blues 1.png
Kyle Blues 2.png
Kyle Person.png
etc
etc
我将如何编写一个 bash 脚本来为每个唯一名称创建一个文件夹。
对于上面的示例,我们将获得文件夹:
Jeff Smith
Jeff Donald
Kyle Reds
Kyle Blues
Kyle Person
etc
我是 bash(以及一般编码)的新手 - 希望能在这方面获得一些帮助
谢谢
答案1
和zsh
:
#! /bin/zsh -
() { mkdir -p -- ${(u)argv%%( <->|).png}; } *.png
在哪里:
() { code; } arguments
.png
是一个匿名函数,它将当前目录中的非隐藏文件列表作为参数(可以通过$argv
或$@
在 中访问code
)。<->
是 zsh glob 运算符,匹配任何十进制数字序列(<first-last>
既没有指定first
也没有last
指定)。${(u)array-expansion}
扩展为数组扩展的唯一元素(删除重复项)。${array%%pattern}
扩展到数组的元素,并删除末尾与 . 匹配的最长字符串pattern
。
因此,在这里,我们为每个由 png 文件组成的唯一字符串创建一个目录,去掉可选的" <digits>"
后跟.png
.
使用bash
GNU 工具,您可以执行类似的操作:
#! /bin/bash -
export LC_ALL=C # needed for sed to deal with arbitrary byte values, for
# [0-9] to match on 0123456789 only and for sort -u to report
# unique records as opposed to one of several that sort the
# same.
shopt -s failglob # to properly handle the cases where there's no png
set -o pipefail # ditto, to report a failure exit status in that case.
printf '%s\0' *.png |
sed -Ez 's/( [0-9]+)?\.png$//' |
sort -zu |
xargs -r0 mkdir -p --
或者避免使用 GNUisms 并使用 bash 4+:
#! /bin/bash -
shopt -s failglob extglob
typeset -A unique
files=(*.png) || exit
for file in "${files[@]}"; do
file=${file%.png}
file=${file% +([0123456789])}
unique[$file]=
done
mkdir -p -- "${!unique[@]}"
请注意,如果当前目录中有一个名为的文件" 12.png"
,则会导致目录名称为空。在上面的最后一个bash
解决方案中,这会导致语法错误,因为bash
关联数组不支持具有空键的元素,并且在所有其他解决方案中,您会收到一个错误,该错误mkdir
将无法创建具有空名称的目录。
请注意,macos 默认情况下不附带 GNU 工具,并且它附带了非常旧版本的bash
.zsh
但它一直伴随着。如果你必须使用bash
那里并且无法安装较新的版本或 GNU 工具,你可以改用perl
:
#! /bin/bash -
perl -e '
for (<*.png>) {
s/\.png\z//;
s/ \d+\z//;
$unique{$_} = undef;
}
$ret = 0;
for (keys %unique) {
unless (mkdir($_) || ($!{EEXIST} && -d $_)) {
warn "Cannot create $_: $!\n";
$ret = 1;
}
}
exit $ret;'
(尽管该代码中没有任何bash
特定内容可以与sh
任何系统一起使用,只要已perl
安装)。