我想制作一个脚本来浏览整个树并删除所有隐藏文件(例如“.git”),除了一些文件(例如“.@__thumb”)。我制作了一个脚本来浏览我的树并删除所有以“.”开头的文件。
这里是:
find . -depth -type d -name '.*' |
while read f
do
dn=`dirname "$f"`
bn=`basename "$f"`
mv "$dn/$bn" "$dn/${bn//.}"
done
然后我想对其进行调整并添加一个条件,以便当我的文件夹/文件名为“.@__thumb”时(这是我不想删除的文件夹),它不会删除“.@__thumb”。
我懂了:
thumb=".@__thumb"
echo $thumb
find . -depth -type d -name '.*' |
while read f
do
if [[ $bn != $thumb ]]
then
dn=`dirname "$f"`
bn=`basename "$f"`
mv "$dn/$bn" "$dn/${bn//.}"
fi
done
不过,我的条件似乎没什么用。我的脚本仍然删除我的“.@__thumb”文件夹。您知道问题出在哪里或有任何改进的想法吗?不知道我的解释是否清楚。如果您有任何疑问,请不要犹豫。非常感谢。
答案1
我在这里假设您想要删除这些隐藏目录名称中的前导点(正如您的代码显然试图做的那样),而不是像您的问题似乎在问的那样删除这些目录本身。
在这里,我会使用zsh
:
autoload -Uz zmv
zmv -n '(**/).(^@__thumb)(#qD/)' '$1$2'
如果满意,请删除-n
(试运行)。
使用find
,您可以使用:
LC_ALL=C find . -depth -name '.?*' ! -name '.@_thumb' -type d -exec sh -c '
for file do
base=${file##*/}
mv -i -T "$file" "${file%/*}/${base#.}"
done' sh {} +
(假设 GNUmv
为-T
)
您的方法不是很稳健,并且存在一些问题:
- 读取一行
read
,语法是IFS= read -r line
, 不是。然而,无论如何,文件路径可以由多行组成,你不能read line
find
这样循环输出。 -name '.*'
匹配名称以 开头.
且后跟的文件零或者更多人物。因此,它将自行匹配.
,并且它将跳过包含在区域设置中不形成有效字符的字节序列的文件名。因此,LC_ALL=C
要确保所有字节都是字符,并.?*
确保至少有一个字符(LC_ALL=C
后的字节.
)。[[ $a = $b ]]
inbash
是检查是否与模式$a
匹配$b
(与 相反!=
)。您需要字节到字节相等比较的[[ $a = "$b" ]]
标准(尽管不包含任何通配符,[ "$a" = "$b" ]
但这里不应该有区别)。.@__thumb
`...`
是已弃用的命令替换的古老形式,我建议您使用现代$(...)
形式。两者都有一个问题,即它们会删除尾随换行符,因此不能用于任意文件名。使用标准sh
${var##*/}
和${var%/*}
运算符而不是目录名/基本名+命令替换可以避免这些问题。- ksh运算
${bn//.}
符删除所有出现的.
in$bn
。所以它将重命名.foo.d
为food
.用于${bn/.}
仅删除第一个出现的字符,或使用标准${bn#.}
删除前导.
字符。 - 如果一个目录同时包含 a
.foo
和foo
dir,mv .foo foo
则变为mv .foo foo/.foo
(它移动.foo
进入(不是到)foo
目录)。-T
避免了这种情况,并-i
让您有机会避免foo
用.foo
.zmv
在执行任何操作之前执行所有健全性检查,因此更加安全。 - 正如@RalfFriedl 已经指出的,您
$bn
在设置之前参考! - 无论如何,如果您将
.git
目录重命名为git
,git
将不再将其父目录视为 git 存储库。如果您重命名.bashrc
为bashrc
,bash
将不再在启动时读取它,等等。
答案2
虽然这通常与编程更相关,但您必须小心指令的顺序。
$bn
在这里,您在条件比较中使用了值,但稍后再计算该值。
所以尝试一下
...
bn=`basename "$f"`
if [[ $bn != $thumb ]]
...