BASH : 自动引用波浪号 (~) 字符
BASH : automatic quoting of tilde (~) character
这里是一个小片段来展示问题
#/usr/bin/bash
RSYNC=/usr/bin/rsync
RSYNC_OPTIONS="-aq --backup --suffix=~ --backup=bkpdir --update"
echo ${RSYNC_OPTIONS}
DOCDIR="Documents" # Note : no trailing slash
BKPDIR="Active-Backups"
HOST=$(hostname)
SRCDIR_DOC="~om/${DOCDIR}/" # Trailing slash added
DESTDIR=$(readlink -f $(dirname "[=11=]") )/${BKPDIR}/${HOST}
echo "DESTDIR = ${DESTDIR}"
echo "Backing up ${SRCDIR_DOC}"
echo "${RSYNC} ${RSYNC_OPTIONS} ${SRCDIR_DOC} ${DESTDIR}/${DOCDIR}"
set -x
${RSYNC} ${RSYNC_OPTIONS} ${SRCDIR_DOC} ${DESTDIR}/${DOCDIR}
set +x
echo "Backup complete."
输出为
[1329]$ bash generic-doc-dow-backup.sh
-aq --backup --suffix=~ --backup=bkpdir --update
DESTDIR = /run/media/om/seagate1/Active-Backups/e6431
+ echo 'Backing up ~om/Documents/'
Backing up ~om/Documents/
+ echo '/usr/bin/rsync -aq --backup --suffix=~ --backup=bkpdir --update ~om/Documents/ /run/media/om/seagate1/Active-Backups/e6431/Documents'
/usr/bin/rsync -aq --backup --suffix=~ --backup=bkpdir --update ~om/Documents/ /run/media/om/seagate1/Active-Backups/e6431/Documents
+ /usr/bin/rsync -aq --backup '--suffix=~' --backup=bkpdir --update '~om/Documents/' /run/media/om/seagate1/Active-Backups/e6431/Documents
rsync: change_dir "/run/media/om/seagate1//~om/Documents" failed: No such file or directory (2)
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1052) [sender=3.0.9]
+ set +x
Backup complete.
正如我们所见,bash 尝试 运行 的实际命令是
/usr/bin/rsync -aq --backup '--suffix=~' --backup=bkpdir --update '~om/Documents/' /run/media/om/seagate1/Active-Backups/e6431/Documents
我不明白的是为什么要引用 ~ (和周围的参数)? Bash 会,但如何停止?
好吧,我通过使用 .bak 后缀和 ${HOME} 获得了脚本 运行ning。我还是很好奇...
谢谢
shell 以某种不可预测的顺序进行各种扩展(~
、通配符扩展、变量替换等)。对于 ~
,在变量赋值中使用(不加引号!)时,它会被您的主路径替换,但在使用变量时不会:
$ var="~" # With quotes, the ~ will be left alone
$ echo "$var"
~
$ echo "$var" # Referencing it without quotes, it still won't be expanded
~
$ var=~ # Without quotes in the assignment, it WILL be expanded
$ echo "$var"
/Users/gordon
...所以一种可能性是使用 $HOME
代替(这将在双引号内展开。另一种方法是将变量赋值的 ~
部分不加引号(如 SRCDIR_DOC=~om/"${DOCDIR}/"
).(实际上,SRCDIR_DOC=~om/${DOCDIR}/
也是安全的,因为不带引号的变量引用的常见问题不适用于赋值——但我更喜欢双引号所有变量引用,而不是试图记住它在哪里安全和不安全的地方。)
但我还建议将选项存储为数组而不是纯字符串变量。这使得这个问题和许多其他潜在问题几乎消失了(参见 BashFAQ #50: I'm trying to put a command in a variable, but the complex cases always fail!)。语法有点复杂,但它确实是执行此类操作的更可靠的方法。此外,双引号变量引用几乎总是一个好主意。最后,我还建议使用小写变量名,以防止与 shell 和其他程序使用的各种特殊变量发生意外冲突(经典示例是分配给 PATH,然后发现 shell找不到任何可执行文件了)。像这样:
#/usr/bin/bash
rsync=/usr/bin/rsync
rsync_options=(-aq --backup --suffix=~ --backup=bkpdir --update)
# printf "%q" will print values with any necessary quoting (but without a
# linefeed at the end, so add an echo afterward); "${arr[@]}" is the standard
# idiom for getting all elements of an array, without word-splitting or
# wildcard expansion.
printf "%q " "${rsync_options[@]}"
echo
docdir="Documents" # Note : no trailing slash
bkpdir="Active-Backups"
host="$(hostname)"
srcdir_doc=~om/"${docdir}/" # Trailing slash added
destdir="$(readlink -f "$(dirname "[=11=]")" )/${bkpdir}/${host}"
echo "destdir = ${destdir}"
echo "Backing up ${srcdir_doc}"
printf "%q " "${rsync}" "${rsync_options[@]}" "${srcdir_doc}" "${destdir}/${docdir}"
echo
set -x
"${rsync}" "${rsync_options[@]}" "${srcdir_doc}" "${destdir}/${docdir}"
set +x
echo "Backup complete."
这里是一个小片段来展示问题
#/usr/bin/bash
RSYNC=/usr/bin/rsync
RSYNC_OPTIONS="-aq --backup --suffix=~ --backup=bkpdir --update"
echo ${RSYNC_OPTIONS}
DOCDIR="Documents" # Note : no trailing slash
BKPDIR="Active-Backups"
HOST=$(hostname)
SRCDIR_DOC="~om/${DOCDIR}/" # Trailing slash added
DESTDIR=$(readlink -f $(dirname "[=11=]") )/${BKPDIR}/${HOST}
echo "DESTDIR = ${DESTDIR}"
echo "Backing up ${SRCDIR_DOC}"
echo "${RSYNC} ${RSYNC_OPTIONS} ${SRCDIR_DOC} ${DESTDIR}/${DOCDIR}"
set -x
${RSYNC} ${RSYNC_OPTIONS} ${SRCDIR_DOC} ${DESTDIR}/${DOCDIR}
set +x
echo "Backup complete."
输出为
[1329]$ bash generic-doc-dow-backup.sh
-aq --backup --suffix=~ --backup=bkpdir --update
DESTDIR = /run/media/om/seagate1/Active-Backups/e6431
+ echo 'Backing up ~om/Documents/'
Backing up ~om/Documents/
+ echo '/usr/bin/rsync -aq --backup --suffix=~ --backup=bkpdir --update ~om/Documents/ /run/media/om/seagate1/Active-Backups/e6431/Documents'
/usr/bin/rsync -aq --backup --suffix=~ --backup=bkpdir --update ~om/Documents/ /run/media/om/seagate1/Active-Backups/e6431/Documents
+ /usr/bin/rsync -aq --backup '--suffix=~' --backup=bkpdir --update '~om/Documents/' /run/media/om/seagate1/Active-Backups/e6431/Documents
rsync: change_dir "/run/media/om/seagate1//~om/Documents" failed: No such file or directory (2)
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1052) [sender=3.0.9]
+ set +x
Backup complete.
正如我们所见,bash 尝试 运行 的实际命令是
/usr/bin/rsync -aq --backup '--suffix=~' --backup=bkpdir --update '~om/Documents/' /run/media/om/seagate1/Active-Backups/e6431/Documents
我不明白的是为什么要引用 ~ (和周围的参数)? Bash 会,但如何停止?
好吧,我通过使用 .bak 后缀和 ${HOME} 获得了脚本 运行ning。我还是很好奇...
谢谢
shell 以某种不可预测的顺序进行各种扩展(~
、通配符扩展、变量替换等)。对于 ~
,在变量赋值中使用(不加引号!)时,它会被您的主路径替换,但在使用变量时不会:
$ var="~" # With quotes, the ~ will be left alone
$ echo "$var"
~
$ echo "$var" # Referencing it without quotes, it still won't be expanded
~
$ var=~ # Without quotes in the assignment, it WILL be expanded
$ echo "$var"
/Users/gordon
...所以一种可能性是使用 $HOME
代替(这将在双引号内展开。另一种方法是将变量赋值的 ~
部分不加引号(如 SRCDIR_DOC=~om/"${DOCDIR}/"
).(实际上,SRCDIR_DOC=~om/${DOCDIR}/
也是安全的,因为不带引号的变量引用的常见问题不适用于赋值——但我更喜欢双引号所有变量引用,而不是试图记住它在哪里安全和不安全的地方。)
但我还建议将选项存储为数组而不是纯字符串变量。这使得这个问题和许多其他潜在问题几乎消失了(参见 BashFAQ #50: I'm trying to put a command in a variable, but the complex cases always fail!)。语法有点复杂,但它确实是执行此类操作的更可靠的方法。此外,双引号变量引用几乎总是一个好主意。最后,我还建议使用小写变量名,以防止与 shell 和其他程序使用的各种特殊变量发生意外冲突(经典示例是分配给 PATH,然后发现 shell找不到任何可执行文件了)。像这样:
#/usr/bin/bash
rsync=/usr/bin/rsync
rsync_options=(-aq --backup --suffix=~ --backup=bkpdir --update)
# printf "%q" will print values with any necessary quoting (but without a
# linefeed at the end, so add an echo afterward); "${arr[@]}" is the standard
# idiom for getting all elements of an array, without word-splitting or
# wildcard expansion.
printf "%q " "${rsync_options[@]}"
echo
docdir="Documents" # Note : no trailing slash
bkpdir="Active-Backups"
host="$(hostname)"
srcdir_doc=~om/"${docdir}/" # Trailing slash added
destdir="$(readlink -f "$(dirname "[=11=]")" )/${bkpdir}/${host}"
echo "destdir = ${destdir}"
echo "Backing up ${srcdir_doc}"
printf "%q " "${rsync}" "${rsync_options[@]}" "${srcdir_doc}" "${destdir}/${docdir}"
echo
set -x
"${rsync}" "${rsync_options[@]}" "${srcdir_doc}" "${destdir}/${docdir}"
set +x
echo "Backup complete."