我有这个简单的代码,可以在清理时创建 .bak 文件。当我再次清理时,bak 文件应该被删除,并且没有 .bak 文件。 bak 它应该回显“没有 .bak”,但它只执行 if 条件。这是代码:
#!/bin/bash
chmod u+x sources/*
if [ "$1" == "clean" ]
then
if [ -f `sources/*.bak` ]
then
rm sources/*.bak
else
echo "there's no .bak files"
fi
elif ["" == "$1"]
then
echo "This script makes a backup for each .c or .h file in sources directory"
target_files=`echo -n $(ls sources/{*.c,*.h})`
echo
echo "Starting to backup: $target_files"
for i in $target_files
do
cp "$i" "$i".bak
done
echo
echo "The following backup files were created: `echo -n $(ls sources/*.bak)`"
echo
echo "Done"
fi
答案1
问题是线
if [ -f `sources/*.bak` ]
反引号`
在 bash 中具有特殊含义:它们用于计算命令并返回其输出。
例如,如果您的用户名是弗罗德尔然后
if [ -f `whoami` ]
将检查是否存在名为frodl
.
因此,如果您编写sources/*.bak
,它会首先尝试 glob 该术语,但由于目录sources/*.bak
中没有具有扩展名的文件,因此该术语不会被扩展。然后它会尝试运行字面术语,这不是有效的命令(实际上你sources/
.bak
sources/*.bak
能有一个名为sources/*.bak
(开头带有星号的文件名;颤抖!)的文件,但似乎您没有。然而,这个文件会有一个.bak
扩展名,这是我们之前排除的。)
如果您确实有一个 file sources/deletemyharddisk.bak
,那么该术语sources/*.bak
将扩展为该字符串,然后尝试执行它(可能会删除您的硬盘)。
所以你需要做的就是使用普通的引号。
backupfiles=sources/*.bak
if [ "x${backupfiles}" = "xsources/*.bak" ]; then
echo "no .bak files" 1>&2
else
echo "there are .bak files"...
fi
这将首先尝试将术语扩展sources/*.bak
到backupfiles
变量中。如果有任何bak文件,这将成为所有文件名的字符串;如果没有,这将保留未展开的字符串。如果然后将结果与文字(未扩展)进行比较,sources/*.bak
您可以判断是否发生了扩展(因为有匹配的文件)。
更好的方法
然而,没有理由首先检查是否有文件然后删除它们。一种更简单的方法是删除与给定模式匹配的所有文件。
find
可以为您做到这一点:
find sources/ -maxdepth 1 -type f -name "*.bak" -delete
(这将在目录的第一级 ( -maxdepth 1
) 中搜索以( ) 结尾sources/
的文件(-type f
; 而不是目录或符号链接或其他内容),然后删除它们 ( ).bak
-name "*.bak"
-delete
不解析ls
您的代码的另一个问题是
target_files=`echo -n $(ls sources/{*.c,*.h})`
for i in $target_files
...
你应该从不解析的输出ls
。
而是使用类似的东西
for i in sources/*.c sources/*h
do
#...
done