动态构建命令


9

我正在编写脚本,因此需要tar动态生成命令。

这是两个示例,以说明我要执行的操作:

#!/bin/bash

TAR_ME="/tmp"

EXCLUDE=("/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*")
_tar="tar "`printf -- '--exclude="%s" ' "${EXCLUDE[@]}"`" -zcf tmp.tar.gz"
echo COMMAND: "${_tar}"
${_tar} "$TAR_ME"

echo -e "\n\nNEXT:\n\n"

EXCLUDE=("--exclude=/tmp/hello\ hello" "--exclude=/tmp/systemd*" "--exclude=/tmp/Temp*")
_tar="tar "`printf -- '%s ' "${EXCLUDE[@]}"`" -zcf test.tar.gz"
echo COMMAND: "${_tar}"
${_tar} "$TAR_ME"

我希望能够_tar用作命令,已经能够使其与经典路径一起使用,但是我需要它与文件夹名称中的空格一起使用。而且每一次我都会看到类似以下的错误:

COMMAND: tar --exclude="/tmp/hello hello" --exclude="/tmp/systemd*" --exclude="/tmp/Temp*"  -zcf tmp.tar.gz /tmp
tar: hello": Cannot stat: No such file or directory

COMMAND: tar --exclude=/tmp/hello\ hello --exclude=/tmp/systemd* --exclude=/tmp/Temp*  -zcf test.tar.gz 
tar: hello: Cannot stat: No such file or directory

您只需要知道一件事,我需要我的脚本才能在非常旧的计算机上工作,这意味着我无法使用最新的bash功能。


我相信--exclude选项在它之后只能接受一个字符串。但是,您可以有多个--exclude语句。也许尝试“ --exclude = / tmp / hello --exclude = hello”糟糕。没关系。我误解了。
Lewis M

@LewisM我认为OP希望排除目录“ / tmp / hello hello”(是的,带有空格
。– Archemar

@ShellCode如何引用所有排除项,例如“ --exclude = / tmp / hello hello”
Archemar

是的 这就是为什么我稍后再发表Oops声明。:)
Lewis M

如何把eval在执行的面前?
jimmij

Answers:


11

不要尝试制作可执行字符串。而是在数组中构建参数并在调用时使用该参数tar(您已经在正确使用数组了EXCLUDE):

#!/bin/bash

directory=/tmp

exclude=( "hello hello" "systemd*" "Temp*" )

# Now build the list of "--exclude" options from the exclude array:
for elem in "${exclude[@]}"; do
    exclude_opts+=( --exclude="$directory/$elem" )
done

# Run tar
tar -cz -f tmp.tar.gz "${exclude_opts[@]}" "$directory"

/bin/sh

#!/bin/sh

directory=/tmp

set -- "hello hello" "systemd*" "Temp*"

# Now build the list of "--exclude" options from the $@ array
# (overwriting the values in $@ while doing so)
for elem do
    set -- "$@" --exclude="$directory/$elem"
    shift
done

# Run tar
tar -cz -f tmp.tar.gz "$@" "$directory"

需要注意的引用$@sh代码和两个${exclude[@]}${exclude_opts[@]}bash代码。这样可以确保将列表扩展为单独引用的元素。

有关:


2
mix(){
        p=$1; shift; q=$1; shift; c=
        i=1; for a; do c="$c $q \"\${$i}\""; i=$((i+1)); done
        eval "${p%\%*}$c${p#*\%}"
}
mix 'tar % -zcf tmp.tar.gz' --exclude "/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*"

EXCLUDE=("/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*")
mix 'tar % -zcf tmp.tar.gz' --exclude "${EXCLUDE[@]}"

这里扩展答案。这不依赖任何bashisms,它也可以与debian's /bin/sh和配合使用busybox


非常感谢您的帮助,但是我真的不喜欢eval,它非常危险...而且,这段代码很难理解,难道您没有一些方便吗?:/该脚本将被分发,所以我必须使其尽可能简单...
ShellCode

没危险 使用运行它set -x。您究竟不了解什么?
mosvy

另外,请阅读有关stackoverflow的原始答案。它包括一个演示。
mosvy

不过,它的效果很好...等待观察是否有人给出了更干净的答案,否则我会接受您的回答。这段代码也许没有什么问题,但是每次我看到一个评估时,我都会担心代码可能导致命令注入,这就是为什么我尝试避免使用它
ShellCode

我已使用针对索引> 9的修复程序更新了答案。您可以将eval替换为回声以查看实际得到的内容(eval看不到文件名)
mosvy
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.