我通常在没有版本控制的服务器上备份配置文件,如下所示:
# cp httpd.conf{,.bak}
# ls
httpd.conf httpd.conf.bak
Run Code Online (Sandbox Code Playgroud)
但是,对于 web 根目录中的文件,我会花时间小心地将.bak
文件扩展名放在文件扩展名之前,以便.php
如果有人设法猜测或探测服务器以获取此类文件,则 Apache 仍将通过 PHP 解释器发送文件:
$ cp index.php index.bak.php
$ ls
index.php index.bak.php
Run Code Online (Sandbox Code Playgroud)
有没有办法使用制表符完成和肌肉记忆将.bak
文件扩展名放在前面?我已经Tab{}?,.bak
陷入了肌肉记忆,我无法在 web 根目录中的文件上使用这个漂亮的“肉宏”。
谢谢。
可能很简单
cp file.{ext,bak.ext}
Run Code Online (Sandbox Code Playgroud)
bash {} 扩展扩展为所有组合(与列出现有文件的 [] 扩展不同。因此它生成两个文件名。
{ .... , .... } 提供了两个选项,因此您可以获得 file.ext 和 file.bak.ext
在您的脚本中,您将使用
cp $FILE.{$EXTENTION,bak.$EXTENTION}
Run Code Online (Sandbox Code Playgroud)
并将 FILENAME 分成两半,您可以使用
FILE=${FILENAME%.*}
EXTN=${FILENAME##*.}
Run Code Online (Sandbox Code Playgroud)
${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
Run Code Online (Sandbox Code Playgroud)
你总是可以使用一个函数:
backup()
for i do
case ${i##*/} in
(?*.?*) cp -iv -- "$i" "${i%.*}.bak.${i##*.}";;
(*) cp -iv -- "$i" "$i.bak"
esac
done
Run Code Online (Sandbox Code Playgroud)
${i##*/}
是的基本名称$i
(即$i
一切到最右边的/
移除),因为我们不想考虑bar/file
作为扩展foo.bar/file
。
然后我们检查是否$i
包含扩展名,即它是否包含至少一个dot
字符,两边都有字符(?*
是任何一个字符后跟0 个或多个字符,所以它是一个或多个字符)。我们不能这样做*.*
,否则我们最好的备份~/.bashrc
作为~/.bak.bashrc
例如。
上面的语法是 POSIX,除了-v
(对于verbose)选项cp
是 GNU 扩展,也可以在其他一些实现中找到,比如 BSD。
然后你可以做这样的事情:
backup foo.php bar.html baz<Tab>...
Run Code Online (Sandbox Code Playgroud)
或者:
backup *.php
Run Code Online (Sandbox Code Playgroud)
不必担心丢失数据(-i
在覆盖文件之前会要求确认,另请参阅-b
GNU 选项cp
)或没有选择正确的名称。