#!/bin/bash
echo "Menu"
echo "1. Backup file"
echo "2. Quit"
echo "Enter Choice"
read Choice
case $Choice" in
1) while :
echo "Enter file name"
read file name
do
if [ -f $filename]
then
current_time=$(date."+%Y.%m.%d")
back_up= "Backup"
new_file=$filename.$back_up.$current_time
echo "New file name is:" "$new_file"
cp $new_file $HOME
else
echo "file does not exists"
fi
done
;;
2) echo "Program Terminated"
exit;;
esac
我需要创建一个 shell 脚本,用于备份用户输入的脚本文件,并使用新的扩展名日期和备份将其保存到主目录,并检查该文件是否存在。第一部分似乎工作正常,但后来我收到一条消息说cp:cannot stat no file or directory
。
答案1
让我们忽略引号、语法等注释以及 Kali-linux 标签不合适的事实,因为它在这里无关紧要,而 Kali 适合有经验的用户。
#!/bin/bash
echo "Menu"
echo "1. Backup file"
echo "2. Quit"
echo "Enter Choice"
read Choice
所以,你现在的选择是或者1
(2
或者我们忽略的许多其他不同的输入)
case "$Choice" in
1) while :
echo "Enter file name"
read file name
do
您读取了 2 个变量file
和name
,但您在脚本的其余部分中均未使用这两个变量。你的意思可能是这样的:
(1) while read -p "Enter file name" filename ; do
if [ -f $filename]
始终为真,因为filename
脚本中为空。如果您阅读filename
而不是file name
,结果将是
bash: [: missing `]'
之前必须插入一个空格]
。 (也可以引用)
if [ -f "$filename" ] ; then
current_time=$(date "+%Y.%m.%d")
back_up="Backup"
new_file="$filename.$back_up.$current_time" # quotes
echo "New file name is: $new_file"
cp $new_file $HOME
您正在输入一个文件名(例如foo
)并且正在复制foo.Backup.2021.03.15
到您的主目录。该文件存在吗?可能不会,因为您收到消息cp: cannot stat foo.Backup.2021.03.15: No such file or directory
So, you might want to copy foo
。
cp "$filename" "$HOME/$new_file"
请注意,您可以通过查看文件名或在cp
. Echos 非常适合查找脚本中的错误。
echo "Copying $filename to $HOME/$new_file"
cp "$filename" "$HOME/$new_file"
else
echo "file does not exists"
fi
done
;;
您需要使用 终止此 while 循环^D
。我希望您没有想到第二个 case 语句会退出循环。
2) echo "Program Terminated"
exit;;
esac
希望有帮助。
答案2
我们假设用户在运行您的脚本时确实想要备份文件。这意味着不需要交互式菜单。 (另请注意声明开头的引用错误case
。)
假设用户可以在脚本的命令行上输入他们想要备份的文件的路径名,可以是整个路径名(可能使用制表符补全,但你的脚本不允许他们这样做),也可以是 shell通配模式(您的脚本也不允许)。这意味着read
可以使用为脚本提供的参数来替换第二个交互式调用和循环。
所以,我们得到
#!/bin/bash
if [ "$#" -eq 0 ]; then
cat >&2 <<END_USAGE
This script backs up files and places backups in your
home directory with a timestamp as filename suffix.
Usage:
$0 file [...]
END_USAGE
exit 1
fi
printf -v suffix 'backup.%(%Y.%m.%d)T' -1
for pathname do
if [ ! -f "$pathname" ]; then
printf '"%s" is not found or is not a regular file, ' "$pathname"
printf 'will not back it up\n'
continue
fi >&2
printf -v newname '%s.%s' "${pathname##*/}" "$suffix"
if cp -i "$pathname" "$HOME/$newname"; then
printf 'backed up "%s" as "%s" in your home directory\n' \
"$pathname" "$newname"
else
printf 'failed backing up "%s" as "%s" in your home directory\n' \
"$pathname" "$newname" >&2
fi
done
执行此操作的唯一原因bash
是能够printf -v
在多个地方使用,并且无需运行date
来获取时间戳(这适用于bash
4.2 或更高版本)。
我正在输出一个简短的信息文本,介绍如何使用该脚本以及在没有任何命令行参数的情况下运行脚本时它会做什么。输出此信息后脚本终止。
如果给定命令行参数($#
大于零),则会迭代这些参数。
在每次迭代中,我们都会检查以确保给定的参数作为常规文件(或到常规文件的符号链接)存在,如果不存在,则跳到下一个。
然后,使用变量suffix
(之前创建的)和当前值的基本名称创建新文件名pathname
。
我们使用 运行副本cp -i
,以便用户有机会对覆盖文件说“不”,以防万一备份文件已经存在。
测试:
$ ./script script
backed up "script" as "script.backup.2021.03.15" in your home directory
$ ./script scriptantoeh
"scriptantoeh" is not found or is not a regular file will not back it up
$ ./script file{1..3}
"file1" is not found or is not a regular file will not back it up
"file2" is not found or is not a regular file will not back it up
"file3" is not found or is not a regular file will not back it up
$ ./script script
overwrite /home/myself/script.backup.2021.03.15? y
backed up "script" as "script.backup.2021.03.15" in your home directory