变量作为bash脚本中的命令

wxs*_*wxs 23 unix bash shell

我正在编写一个非常简单的bash脚本,它对目标目录进行加密,对其输出进行加密,然后将生成的文件拆分为多个较小的文件,因为备份介质不支持大文件.

我对bash脚本没有太多经验.我相信我在正确引用我的变量以允许参数中的空格时遇到问题.该脚本如下:

#! /bin/bash

# This script tars the given directory, encrypts it, and transfers
# it to the given directory (likely a USB key).

if [ $# -ne 2 ]
then
    echo "Usage: `basename $0` DIRECTORY BACKUP_DIRECTORY"
    exit 1
fi

DIRECTORY=$1
BACKUP_DIRECTORY=$2
BACKUP_FILE="$BACKUP_DIRECTORY/`date +%Y-%m-%dT%H-%M-%S.backup`"

TAR_CMD="tar cv $DIRECTORY"
SPLIT_CMD="split -b 1024m - \"$BACKUP_FILE\""

ENCRYPT_CMD='openssl des3 -salt'

echo "$TAR_CMD | $ENCRYPT_CMD | $SPLIT_CMD"

$TAR_CMD | $ENCRYPT_CMD | $SPLIT_CMD 

say "Done backing up"
Run Code Online (Sandbox Code Playgroud)

运行此命令失败:

拆分:"foo/2009-04-27T14-32-04.backup"aa:没有这样的文件或目录

我可以通过删除$BACKUP_FILE我设置的位置周围的引号来解决它$SPLIT_CMD.但是,如果我的备份目录名称中有空格,则它不起作用.此外,如果我将"echo"命令的输出直接复制并粘贴到终端,它可以正常工作.显然,我不明白Bash是如何逃避事情的.

Jul*_*ano 45

只是不要将整个命令放在变量中.尝试恢复引用的参数会遇到很多麻烦.

也:

  1. 避免在脚本中使用全大写变量名称.轻松拍摄自己的脚.
  2. 不要使用反引号,而是使用$(...),它更好地嵌套.

#! /bin/bash

if [ $# -ne 2 ]
then
    echo "Usage: $(basename $0) DIRECTORY BACKUP_DIRECTORY"
    exit 1
fi

directory=$1
backup_directory=$2
current_date=$(date +%Y-%m-%dT%H-%M-%S)
backup_file="${backup_directory}/${current_date}.backup"

tar cv "$directory" | openssl des3 -salt | split -b 1024m - "$backup_file"
Run Code Online (Sandbox Code Playgroud)

  • 我不明白1.关心解释?如何/为什么更容易在脚下射击? (9认同)
  • ata:因为你可能无意中破坏了环境变量(总是大写)? (7认同)
  • @wxs:将命令放在变量中没有任何优雅.你没有获得任何灵活性; 相反,你只是因为分词而导致错误.您可能打算做的是将命令放在函数中.你执行功能.你永远不应该执行变量内容.永远. (4认同)
  • @ata:请参阅http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html中有关环境变量名称的POSIX约定 - 显式地,全部大写名称由对操作系统或shell有意义的变量使用并且保证使用至少一个小写字符的名称对于应用程序的使用是安全的,而不会无意中修改shell行为. (4认同)

Cha*_*ffy 8

eval如果您的目录名称可以由不受信任的源生成,则不是可接受的做法.有关不应使用的原因的详细信息,请参阅BashFAQ#48 ;有关此问题及其正确解决方案的根本原因,请参阅BashFAQ#50,其中一些内容如下所示:eval

如果需要随着时间的推移构建命令,请使用数组:

tar_cmd=( tar cv "$directory" )
split_cmd=( split -b 1024m - "$backup_file" )
encrypt_cmd=( openssl des3 -salt )
"${tar_cmd[@]}" | "${encrypt_cmd[@]}" | "${split_cmd[@]}"
Run Code Online (Sandbox Code Playgroud)

或者,如果这只是在一个中心位置定义命令,请使用函数:

tar_cmd() { tar cv "$directory"; }
split_cmd() { split -b 1024m - "$backup_file"; }
encrypt_cmd() { openssl des3 -salt; }
tar_cmd | split_cmd | encrypt_cmd
Run Code Online (Sandbox Code Playgroud)


Edd*_*die 6

我不确定,但可能值得先在命令上运行eval.

这将让bash将变量$ TAR_CMD扩展到它们的全宽度(正如echo命令对控制台所做的那样,你认为有效)

然后,Bash会在扩展变量的情况下第二次读取该行.

eval $TAR_CMD | $ENCRYPT_CMD | $SPLIT_CMD 
Run Code Online (Sandbox Code Playgroud)

我刚刚进行了谷歌搜索,这个页面似乎可以很好地解释为什么需要它. http://fvue.nl/wiki/Bash:_Why_use_eval_with_variable_expansion%3F