关于bash:想要通过将其输出重定向到变量来检查命令是否成功

Want to check whether a command succeeded by redirecting its output to a variable

我目前正在编写一个bash脚本,它使用GoogleCl将视频文件加载到YouTube。

当我在一个循环中进行上传时(因为可能有多个视频文件),我想在上传下一个文件之前检查每个文件是否成功上传。

命令google youtube post --access unlisted --category Tech $f(其中$f代表文件)输出一个字符串,告诉我上传是否成功。

但我不知道如何将"返回字符串"重定向到变量中以检查成功。

我就是这么想的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
for f in ./*.ogv ./*.mov ./*.mp4
do
    if [[ '*' != ${f:2:1} ]]
    then
        echo"Uploading video file $f"

        # How to put the return value of the following command into a variable?
        google youtube post --access unlisted --category Tech $f > /dev/null

        # Now I assume that the output of the command above is available in the variable RETURNVALUE
        if [[ $RETURNVALUE == *uploaded* ]]
        then
            echo"Upload successful."
        else
            echo"Upload failed."
        fi
    fi
done

有人能帮我吗?


我猜你也可以依赖于google命令中的错误代码(我假设如果上传失败它会返回错误,但是你应该仔细检查一下)。

1
2
3
4
5
6
7
8
9
10
11
12
13
for f in ./*.ogv ./*.mov ./*.mp4; do
  if [[ '*' != ${f:2:1} ]]; then

    echo"Uploading video file $f"
    if google youtube post --access unlisted --category Tech"$f"> /dev/null
    then
      echo"Upload successful."
    else
      echo"Upload failed."
    fi

  fi
done

一个常见的误解是,如果希望用括号括起来的表达式来计算,如果总是接受一个命令并检查错误状态,那么这是不正确的;通常这个命令是[,它是test的别名,用于计算表达式。(是的,如果没有一个优化的快捷方式使它在bash中运行得更快,我会感到惊讶,但从概念上讲,它仍然是正确的)。

捕获输出是通过倒计时完成的,就像这样

1
result=`command argument a b c`

或者使用$()

1
result=$(command argument a b c)

但在这种情况下,最好使用错误代码。

编辑:你的工作很有趣。我一开始没有注意到,但是如果启用nullglobshell选项(如果没有文件,这将使./*.mov扩展到空字符串),就可以避免。另外,引用$f或者如果文件名包含空格,它将中断。

1
2
3
4
5
6
7
8
9
10
shopt -s nullglob
for f in ./*.ogv ./*.mov ./*.mp4; do
  echo"Uploading video file $f"
  if google youtube post --access unlisted --category Tech"$f"> /dev/null
  then
    echo"Upload successful."
  else
    echo"Upload failed."
  fi
done

Hth.


我称之为"EDOCX1"(10)。return'是一个关键字,返回值是一个数字,其中0表示按约定成功(0个错误),另一个值表示错误代码。

通过以下方式获取输出:

1
result=$(google youtube post --access unlisted --category Tech $f)

但往往会看到劣质的解决方案:

1
result=`cmd param1 param2`

次优,因为反勾很容易与撇号混淆(取决于字体),并且很难嵌套,所以不要使用它们。

摘自《男人的狂欢》:

The return value of a simple command
is its exit status, or 128+n if the
command is terminated by signal n.

还有:

return [n]
Causes a function to exit with the return value specified
by n. If n is omitted, the return
status is that of the last
command executed in the function body. If used outside a
function, but during execution of a
script by the . (source)
command, it causes the shell to stop executing that script
and return either n or the exit status
of the last command
executed within the script as the exit status of the
script. If used outside a function
and not during execution of a
script by ., the return status is false. Any command
associated with the RETURN trap is
executed before execution
resumes after the function or script.

最后一个命令的返回值/退出代码是通过$?.

您所指含义的关键字是命令替换。又一次"男人狂欢"了:

Command Substitution
Command substitution allows the output of a command to replace the
command name. There are two forms:

1
2
3
          $(command)
   or
          `command`

Bash performs the expansion by executing command and replacing the command substitution with the standard
output of the command, with any trailing newlines deleted. Embedded newlines
are not deleted, but they may be
removed during word splitting.
The command substitution $(cat file) can be replaced by the
equivalent but faster $(< file).

1
   When  the old-style backquote form of substitution is used,

backslash retains its literal meaning
except when followed by $, `,
or . The first backquote not preceded by a backslash terminates the
command substitution. When using the
$(command) form,
all characters between the parentheses make up the command; none
are treated specially.

1
   Command substitutions may be nested.  To nest when using the

backquoted form, escape the inner
backquotes with backslashes.

If the substitution appears within double quotes, word splitting
and pathname expansion are not
performed on the results.


如果在> /dev/null之后仍然得到输出,那么它将在stderr上输出,因此标准的backticks或$()将不起作用。

首先,查看返回代码是否指示问题:examine$?在成功和失败之后。

如果返回代码不够,可以重定向输出:

1
RETURNVALUE=$(google youtube post --access unlisted --category Tech $f 2>&1 >/dev/null)

2>&1将stderr放在stdout fd上,然后再将stdout重定向为Nothing。


使用$()

1
variable=$(google youtube post --access unlisted --category Tech $f )


问题的答案是使用read命令。

当然,所有这些其他的答案都显示出了不去做OP要求的事情的方法,但这真的让我们这些寻找OP问题的人搞砸了。

免责声明:这是重复的答案

以下是你的做法…命令:

1
2
3
4
5
6
7
8
9
# I would usually do this on one line, but for readability...
series | of | commands \
| \
(
  read string;
  mystic_command --opt"$string" /path/to/file
) \
| \
handle_mystified_file

以下是它所做的以及为什么它很重要:

  • 假设series | of | commands是一系列非常复杂的管道命令。
  • mystic_commandis可以接受stdin作为文件,但不能接受选项arg,因此它必须作为变量输入**
  • read接收stdin并将其放入变量$string中。
  • 不需要通过括号将readmystic_command放入"子shell"中,但会使其像一个连续的管道一样流动,就像2命令在单独的脚本文件中的位置一样。
  • **总有一个备选方案,在这种情况下,备选方案是丑陋的,不可读的:

    1
    mystic_command --opt"$(series | of | commands)" /path/to/file | handle_mystified_file

    访问YouTube的示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    rm ~/temp/youtube_top_title1.txt
    rm ~/temp/youtube_top1.txt
    curl "http://www.youtube.com/"|\
    grep -o 'watch[^"]*'|\
    sort -n|\
    uniq -c|\
    awk '{if ($1!="1") print $2}'|\
    while read i ; do\
        page_youtube=`curl -s "http://www.youtube.com/${i}"`;\
        echo `echo -e"$page_youtube" |awk '{if ($1 ~"") start=1; if ($1 ~"") start=0; if (start == 1) print $0 }'|grep -v ''` >> ~/temp/youtube_top_title1.txt
        url_current=$(echo -e"$page_youtube"|\
        grep -o"url=[^,]*,"|\
        sed 's/url=//g;s/,//g'|\
        php -r '$f=fopen("php://stdin","r");while (FALSE!==($line=fgets($f))) echo urldecode($line);'|\
        awk '{print $1}'|\
        sed 's/;$//g'|\
        sed 's/\\u.*//g'|\
        tail -2|\
        head -1)
        echo"$url_current">> ~/temp/youtube_top1.txt
    done


    您可以使用反勾号将其分配给变量:

    1
    CONTENT=`google youtube post --access unlisted --category Tech $f > /dev/null`