在包含管道的bash中执行字符串作为命令

时间:2014-09-04 10:14:20

标签: linux bash

我正在尝试列出一些ftp目录。我无法弄清楚如何使bash执行包含正确管道的命令。

这是我的剧本:

#/bin/sh

declare -a dirs=("/dir1" "/dir2")           # ... and lots more
for d in "${dirs[@]}"
do
    cmd='echo "ls /mydir/'"$d"'/*.tar*" | sftp -b - -i ~/mykey user@example.com 2>&1 | tail -n1'
    $cmd
done

这只是输出:

"ls /mydir/dir1/*.tar*" | sftp -b - -i ~/mykey user@example.com 2>&1 | tail -n1
"ls /mydir/dir2/*.tar*" | sftp -b - -i ~/mykey user@example.com 2>&1 | tail -n1

如何让bash执行包括echo在内的整个字符串?我还需要能够解析命令的输出。

3 个答案:

答案 0 :(得分:3)

我根本不认为您需要使用-b开关。指定要作为字符串执行的命令应该足够了:

#/bin/bash

dirs=("/dir1" "/dir2")
for d in "${dirs[@]}"
do
    printf -v d_str '%q' "$d"
    sftp -i ~/mykey user@example.com "ls /mydir/$d_str/*.tar*" 2>&1 | tail -n1       
done

正如comments中所建议的那样(感谢@Charles),我已使用printf%q格式说明符来防止目录名称中可能被解释的字符由壳。

答案 1 :(得分:1)

不要将命令存储在字符串中;直接使用它。

#/bin/bash

declare -a dirs=("/dir1" "/dir2")           # ... and lots more
for d in "${dirs[@]}"
do
  echo "ls /mydir/$d/*.tar*" | sftp -b - -i ~/mykey user@example.com 2>&1 | tail -n1
done

通常,人们将命令存储在一个字符串中,这样他们就可以执行它并将其记录下来,作为一种误导形式的因子分解。 (我认为它不值得做正确的麻烦。)

请注意,sftp默认从标准输入读取,因此您只需使用

echo "ls ..." | sftp -i ~/mykey user@example.com 2>&1 | tail -n1

您也可以使用here文档而不是管道。

sftp -i ~/mykey user@example.com 2>&1 <<EOF | tail -n1
ls /mydir/$d/*.tar.*
EOF

答案 2 :(得分:0)

首先,您需要使用/bin/bash作为shebang来使用BASH数组。

然后删除echo并使用命令替换来捕获输出:

#/bin/bash

declare -a dirs=("/dir1" "/dir2")           # ... and lots more
for d in "${dirs[@]}"
do
    output=$(ls /mydir/"$d"/*.tar* | sftp -b - -i ~/mykey user@example.com 2>&1 | tail -n1)
    echo "$output"
done

但我建议您不要在ls命令中使用sftp的输出。您可以将其替换为:

output=$(echo "/mydir/$d/"*.tar* | sftp -b - -i ~/mykey user@example.com 2>&1 | tail -n1)