Fro*_*d0n 1 linux bash shell-script
我想制作一个脚本来浏览我的整个树并删除所有隐藏文件(例如“.git”),除了一些(例如“.@__thumb”)。我制作了一个脚本来浏览我的树并删除所有以“.”开头的文件。
这里是:
find . -depth -type d -name '.*' |
while read f
do
dn=`dirname "$f"`
bn=`basename "$f"`
mv "$dn/$bn" "$dn/${bn//.}"
done
Run Code Online (Sandbox Code Playgroud)
然后我想调整它并添加一个条件,以便当我的文件夹/文件被称为“.@__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
Run Code Online (Sandbox Code Playgroud)
然而,我的条件似乎没有用。我的脚本仍然会删除我的“.@__thumb”文件夹。你知道问题可能来自哪里或任何改进的想法吗?我不知道我的解释是否清楚。如果您有任何疑问,请不要犹豫。非常感谢。
我在这里假设您想删除那些隐藏目录名称中的前导点(正如您的代码显然试图这样做),而不是像您的问题所问的那样删除这些目录本身。
在这里,我会使用zsh
:
autoload -Uz zmv
zmv -n '(**/).(^@__thumb)(#qD/)' '$1$2'
Run Code Online (Sandbox Code Playgroud)
-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 {} +
Run Code Online (Sandbox Code Playgroud)
(假设 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%/*}
运算符而不是目录名/基名 + 命令替换可以避免这些问题。${bn//.}
KSH操作消除了所有出现.
在$bn
。所以它会重命名.foo.d
为food
. 用于${bn/.}
仅删除第一次出现,或${bn#.}
用于删除前导.
字符的标准。.foo
和foo
目录,mv .foo foo
成为mv .foo foo/.foo
(它移动.foo
到(不给)的foo
目录)。-T
避免了这种情况,并-i
让您有机会避免foo
使用.foo
. zmv
在执行任何操作之前执行所有健全性检查,因此更安全。$bn
在设置之前参考!.git
目录重命名为git
,git
将不再将其父目录视为 git 存储库。如果您重命名.bashrc
为bashrc
,bash
则在开始时将不再读取它,等等。