我一直在一个简单的目录结构上对此进行测试。
我正在尝试将名称为“Season”的任何目录和/或子目录更改为“Sn”。我已经到了脚本会更改我想要的内容的地步......除了顶级目录之外,如下面的列表所示 - “第 1 季”“第 2 季”“第 3 季”。
目录结构:
.
├── AnotherShow
│ ├── Sn1
│ ├── Sn2
│ ├── Sn3
│ └── Sn4
├── Movie1
│ ├── Sn1
│ └── Sn2
├── Movie2
│ ├── Sn1
│ ├── Sn2
│ ├── Sn3
│ └── Sn4
├── Movie3
│ ├── Sn1
│ └── Sn3
├── Movie4
│ ├── Sn2
│ └── Sn3
├── Season 1
├── Season 2
├── Season 3
├── Show
│ ├── Sn1
│ ├── Sn2
│ ├── Sn3
│ ├── Sn4
│ └── Sn5
└── TV
├── Sn1
├── Sn2
├── Sn3
└── Sn4
我的脚本是:
array="$(find . -maxdepth 2 -type d -iname 'Season*' -print)"; # A more refined way to search for Seasons in a directory.
for dir in "${array[@]}"; do # Put this list into an array. Surround the array with quotes to keep all space s (if any) together.
new="$(echo "$dir" | sed -e 's/Season 0/Sn/' -e 's/Season /Sn/')"; # Only change Season 0 to SN. Leave othe rs alone.
sudo mv -v "$dir" "$new" && echo Changed "$dir" to "$new";
done
答案1
问题是您不是在创建数组,而是在创建字符串。您可以通过尝试打印数组的第一个元素来轻松测试这一点:
$ array="$(find . -maxdepth 2 -type d -iname 'Season*' -print)";
$ echo $array
./Season 3 ./Season 1 ./Season 2
看起来不错吧?但如果这是一个数组,您将能够单独打印每个元素。不幸的是,上面是一个简单的字符串1而不是数组:
$ echo ${array[0]}
./Season 3 ./Season 1 ./Season 2
$ echo ${array[1]}
该数组实际上由单个字符串组成,这就是“数组”的第二个元素 ( ${array[1]}
) 为空的原因。在任何情况下,您都不需要为此使用数组,只需读取 的输出find
(您也不需要-print
,这就是它默认执行的操作)。您的脚本的工作版本可能是:
#!/usr/bin/env bash
find . -maxdepth 2 -type d -iname 'Season*' | sort -r |
while IFS= read -r dir
do
mv "$dir" ${dir/Season /Sn} && echo Changed "$dir" to "$dir/Season /Sn}";
done
这里使用了一些技巧。首先,while
循环遍历 的结果find
。这与您使用的循环的基本原理相同,for
但与之结合read
可以从标准输入读取。
需要IFS=
避免在空格上分割(没有它,目录Season 1
将被分割为Season
和1
)。
of -r
read 告诉它不允许反斜杠转义字符(像\t
和 之类的东西\n
按字面意思处理),这确保它可以处理最奇怪的名称。
这sort -r
是必需的,这样如果您有一个与另一个匹配目录中的模式匹配的目录,则子目录会列在父目录之前。例如:
./Season 12/Season 13
./Season 12
这可以确保您运行mv "Season 12" "Sn12"
后跑步mv "Season 12"/"Season 13" "Season 12"/"Sn13"
。如果不这样做,第二个命令将失败,因为Season 12
不再存在。
最后,我删除了sudo
.您应该将脚本运行为sudo script.sh
.sudo
在脚本中进行随机调用从来都不是一个好主意。
1我不确定细节,但显然,bash 将字符串变量视为一个元素的数组。
答案2
我还不知道问题是什么,但我对你的脚本有一些评论。
尽量不要在循环中调用二进制文件(带有单个数据)。这会影响性能。
您应该使用 sudo 调用整个脚本,但不要在脚本内调用 sudo。
您不需要sed
更改文件名。bash
可以自己做:
if [[ $dir =~ "Season 0" ]]; then
new="${dir/Season 0/Sn}"
else
new="${dir/Season /Sn}"
fi
或者没有if
:
new="${dir/Season /Sn}"
new="${new/Sn0/Sn}"
你不需要数组:
find ... | while read dirpath; do
这样做的“优点”是目录名称中的空格不会破坏数组定义。我不知道你为什么array="$(find ... -print)"
工作。它不应该(因为 shell 不应该在空格和换行符之间进行单词分割)。
答案3
只是上面的简短变体
for dir in ./*/Season\ */
do
mv "$dir" "${dir/eason /n}" && echo "$dir changed to ${dir/eason /n}"
done
与子目录一起使用季节。如果您想重命名文件(不仅仅是目录),只需/
在模式末尾删除,这样它看起来像./*/Season\ *
如果您需要,sudo
我会建议您使用一行命令(而不是脚本)来完成此操作
for dir in ./*/Season\ */ ; do sudo mv -v "$dir" "${dir/eason /n}" ; done