我通常在没有版本控制的服务器上备份配置文件,如下所示:
# cp httpd.conf{,.bak}
# ls
httpd.conf httpd.conf.bak
但是,对于 Web 根目录中的文件,我会花时间仔细地将 放在.bak
文件扩展名之前,以便.php
保留 和 Apache 仍将通过 PHP 解释器发送文件(如果有人设法猜测或探测服务器中是否存在此类文件):
$ cp index.php index.bak.php
$ ls
index.php index.bak.php
有没有办法使用制表符补全和肌肉记忆将 放在.bak
文件扩展名之前?我已经Tab{}←,.bak
记住了肌肉记忆,我无法在网络根目录中的文件上使用这个漂亮的“肉宏”。
谢谢。
答案1
可能很简单
cp file.{ext,bak.ext}
bash {} 扩展扩展为所有组合(与列出现有文件的 [] 扩展不同。因此它生成两个文件名。
{ .... , .... } 提供了两个选项,因此您可以获得 file.ext 和 file.bak.ext
在你的脚本中你会使用
cp $FILE.{$EXTENTION,bak.$EXTENTION}
要将 FILENAME 分成两半,您可以使用
FILE=${FILENAME%.*}
EXTN=${FILENAME##*.}
${VAR%xxxxx} 将返回 VAR 中内容的左侧直至匹配模式,在上面的情况下,模式为 .*,因此您将获得除最后一个 .* 之外的所有内容
${VAR##xxxxx} 将返回 VAR 中匹配模式之后内容的右侧。双哈希意味着获得最大可能的匹配,以防存在多个可能的匹配。
要保存脚本,请检查获取 FILE 和 EXTENTION 后是否存在不同的情况。如果文件名没有扩展名,就会发生这种情况。
脚本的一个子部分可能如下所示:
ls *html | while read FILENAME
do
FILE=${FILENAME%.*}
EXTN=${FILENAME##$FILE}
cp $FILE{$EXTN,.bak$EXTN}
done
答案2
您始终可以使用一个函数:
backup()
for i do
case ${i##*/} in
(?*.?*) cp -iv -- "$i" "${i%.*}.bak.${i##*.}";;
(*) cp -iv -- "$i" "$i.bak"
esac
done
${i##*/}
是 的基本名称$i
(即删除了$i
最右边的所有内容/
),因为我们不想将bar/file
其视为foo.bar/file
.
然后我们检查是否$i
包含扩展名,即是否至少包含一个dot
两边都有字符的字符(?*
是任意一个字符其次是0 个或多个字符, 所以就是一个或多个字符)。例如,我们不能这样做*.*
,否则我们会进行备份。~/.bashrc
~/.bak.bashrc
上面的语法是 POSIX,除了-v
(for冗长的) 选项cp
是 GNU 扩展,也可以在 BSD 等其他一些实现中找到。
然后你可以做这样的事情:
backup foo.php bar.html baz<Tab>...
或者:
backup *.php
不必担心丢失数据(-i
在覆盖文件之前会要求确认,另请参阅-b
GNU 选项cp
)或没有选择正确的名称。
答案3
我无法立即想出一种方法来完成制表符,除了可能还保留一份不带扩展名的文件名副本,这样您就可以一次性添加“bak.php”。但我的解决方案是一个小的 shell 脚本,它将文件名作为输入并将其复制到“firstpart.bak.extension”。
答案4
我在几个没有源代码控制的 UNIX 系统上遇到了这个问题,并且需要快速进行小的更改。对于这样的情况,我使用脚本来剪切文件,以剪切带有时间戳的副本,以便快速恢复。 ls 显示其后按文件名排序的版本日期的文件。
if [ "$1" = "" ]; then
echo "File name required. Aborting."
exit 1
fi
CDATE=`date +%Y-%m-%d-%H-%M`
cp "$1" "$1-$CDATE"
echo File backed up to: $1-$CDATE
用法:
VERS.sh httpd.conf
输出:
File backed up to: httpd.conf-2016-07-14-10-27