Linux bash tar错误不存在';t创建tar.gz

Linux bash tar错误不存在';t创建tar.gz,linux,bash,tar,Linux,Bash,Tar,我有以下bash脚本: #DIR is something like: /home/foo/foobar/test/ without any whitespace but can also include whitespace DIR="$( cd "$( dirname "$0" )" && pwd )" #backup_name is read from a file backup_name=FOOBAR date=`date +%Y%m%d_%H%M_%S` #subdir

我有以下bash脚本:

#DIR is something like: /home/foo/foobar/test/ without any whitespace but can also include whitespace
DIR="$( cd "$( dirname "$0" )" && pwd )"
#backup_name is read from a file
backup_name=FOOBAR
date=`date +%Y%m%d_%H%M_%S`
#subdirs is also read from the same file
subdirs=etc/ sbin/ bin/
filename="$DIR/Backup_$backup_name"_"$date.tar.gz"

cd /
echo "filename: $filename"
echo "subdirs $subdirs"
cmd='tar czvf "'$filename'" '$subdirs
echo "cmd tar: $cmd"
$cmd
但我得到以下输出:

filename: /home/foo/foobar/test/Backup_FOOBAR_20120322_1529_35.tar.gz
subdirs: etc/ sbin/ bin/
cmd tar: tar cfvz "/home/foo/foobar/test/Backup_FOOBAR_20120322_1529_35.tar.gz" etc/ sbin/ bin/
etc/
# ... list of files in etc
# but no files from sbin or bin directory
tar: "/home/foo/foobar/test/Backup_FOOBAR_20120322_1529_35.tar.gz": can open not execute: File or directory not found
tar: not recoverable error: abortion.
但是,当我复制tar命令的echo输出时,制作一张cd到/并将其粘贴到bash shell中,它正在工作:

tar cfvz "/home/foo/foobar/test/Backup_FOOBAR_20120322_1529_35.tar.gz" etc/ sbin/ bin/
etc/
  • 每个变量都已定义,并且没有尾随换行符
  • 我还尝试了$cmd和backticks
  • 这两个变量:backup_name和subdir是从文件中读取的(我在代码中没有包括读取过程)
编辑:我刚刚将脚本复制到一个没有空格的目录,并更改了行:

cmd='tar czvf "'$filename'" '$subdirs
#to
cmd="tar czvf $filename $subdirs"
它现在可以工作了,但是当我在包含空白的目录中做同样的操作时,我仍然会得到相同的错误

edit2:读取文件(在其他任何事情发生之前读取文件)

config=“config.txt”
本地线路
读行时
做
#指向下一个自由元素并声明它
配置行[${配置行[@]}]=$line

完成我建议您将$cmd与$filename和$subdirs分开。我认为,当您连接这些字符串时,会产生诱发错误。此外,在一个变量中使用多个变量而不适当引用也会导致错误

这应该适合您:

cmd="tar -zcvf"
subdirs="etc/ sbin/ bin/"
filename="${DIR}/Backup_${backup_name}_${date}.tar.gz"
$cmd $filename $subdirs

如果执行字符串$cmd,如果“filename”嵌入空格,则该字符串将不起作用 必须让bash创建参数。 像这样:

tar czvf“${filename}”$subdirs


你甚至不需要把“\”放在文件名中,而不用纠结于混乱的引用问题,你可以用不同的方式得到你想要的结果,或许还可以节省一些时间。像这样的怎么样

#!/usr/bin/env bash

# abusing set -v for fun and profit

tar_output=/tmp/$$.tarout
tar_command=/tmp/$$.tarcmd
tmp_script=/tmp/$$.script

dir="$(cd "$(dirname "$0")"; pwd)"

cat>"${tmp_script}"<<-'END'
datestamp=$(date +%Y%m%d_%H%M_%S)
subdirs=(etc sbin bin)
backup_name=FOOBAR
filename="$1/Backup_${backup_name}_${date}.tar.gz"

printf 'tar cmd: '
set -v
tar czvf "$filename" "${subdirs[@]}" 2>"$2"
set +v
END

bash "${tmp_script}" "$dir" "${tar_output}" 2>"${tar_command}"
cat "${tar_command}" | head -n 1 | sed -e 's/2>"\$2"$//'
cat "${tar_output}"

rm -f "${tmp_script}" "${tar_command}" "${tar_output}"
#/usr/bin/env bash
#滥用set-v以获取乐趣和利润
tar_输出=/tmp/$$.tarout
tar_命令=/tmp/$$.tarcmd
tmp_script=/tmp/$$.script
dir=“$(cd“$(dirname“$0”)”pwd)
cat>“${tmp_脚本}”“${tar_命令}”
cat“${taru命令}”head-n1 | sed-e's/2>“\$2”$/'
cat“${tar_output}”
rm-f“${tmp_脚本}”${tar_命令}”${tar_输出}”

我对此深表歉意,但在现实世界中请注意,您希望生成正确的临时文件。

好的,您的原始脚本不起作用,因为文件/路径确定发生在变量扩展之前,因此文件名是错误的:
tar
认为它应该写入当前目录中名为
“/home/foo/foobar/test/Backup\u foobar\u 20120322\u 1529\u 35.tar.gz”
即文件名包含斜杠和双引号

tar cfz /this/file/does/nopt/exist .
tar: /this/file/does/nopt/exist: Cannot open: No such file or directory
tar: Error is not recoverable: exiting now
看到区别了吗?在
tar
的错误消息中,文件名/路径周围没有双引号

当您复制并粘贴行时,它起作用,因为这样,双引号由shell进行解释

证人:

ls -l /tmp/screen-exchange
-rw-rw-rw- 1 aqn users 0 Mar 21 07:29 /tmp/screen-exchange
cmd='ls -l "'/tmp/screen-exchange'"'
$cmd
/bin/ls: "/tmp/screen-exchange": No such file or directory
eval $cmd
-rw-rw-rw- 1 aqn users 0 Mar 21 07:29 /tmp/screen-exchange
当然,使用
eval
不会防止文件名中包含空格。要防止出现这种情况,您的
tar
命令需要如下所示:

date>'file name with spaces'
file='file name with spaces'  # this is the equivalent of your $filename
cmd='ls -l "$file"'
$cmd
ls: "$file": No such file or directory
eval $cmd
-rw-r--r--  1 andyn  SPICE\Domain Users  1083 Mar 22 15:28 a b
简短回答:见

长答案:在变量中嵌入引号没有任何用处,因为当您使用它(即
$cmd
)时,bash会在替换变量之前解析引号;当引号出现时,对它们来说做任何好事都为时已晚。但是,您有几个选项:

  • 首先不要麻烦将命令放在变量中,直接使用它即可:

    echo "filename: $filename"
    echo "subdirs $subdirs"
    tar czvf "$filename" $subdirs
    
  • 如果确实需要首先将其放入变量中,请使用数组而不是纯文本变量(理想情况下,对subdirs列表执行相同操作):


  • f应该是最后一个选项,因为它使用tar file参数。请尝试使用相同的
    tar czvf
    ,但thx获取信息。请编辑您的帖子,以包含
    $config
    文件中有问题的行。祝您好运。我没有引用subdirs和backup\u name,因为我是从文件中读取的。但即使我引用subdirs=”etc/sbin/bin/“就像你建议的那样,它将被视为一个不存在的目录。@杰克,请附上你是如何从文件中读取子目录的。引用它对我有用。thx,“${filename}”和“$filename”变量之间有什么区别?“$filename”是“${filename}”的特例“在这个特定场景中也是一样,更一般的${…}允许进一步的替换和其他微妙之处。
    date>'file name with spaces'
    file='file name with spaces'  # this is the equivalent of your $filename
    cmd='ls -l "$file"'
    $cmd
    ls: "$file": No such file or directory
    eval $cmd
    -rw-r--r--  1 andyn  SPICE\Domain Users  1083 Mar 22 15:28 a b
    
    echo "filename: $filename"
    echo "subdirs $subdirs"
    tar czvf "$filename" $subdirs
    
    subdirs=(etc/ sbin/ bin/)
    ...
    
    echo "filename: $filename"
    echo "subdirs ${subdirs[*]}"
    cmd=(tar czvf "$filename" "${subdirs[@]}")
    printf "cmd tar:"
    printf " %q" "${cmd[@]}" # Have to do some trickery to get it printed right
    printf "\n"
    "${cmd[@]}"