23

I'm currently writing a bash script which loads video files up to to YouTube using GoogleCL.

As I'm doing this uploading stuff in a loop (because there can be multiple video files) I would like to check if each file had been uploaded successfully before I upload the next one.

The command google youtube post --access unlisted --category Tech $f (where $f represents the file) outputs a string which tells me whether the upload has been successful or not.

But I don't know how to redirect that "return string" into a variable to do check the successs.

That's what I have:

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

Can anybody help me?

einpoklum
  • 118,144
  • 57
  • 340
  • 684
Patrick
  • 3,091
  • 4
  • 26
  • 29

7 Answers7

21

My guess is that you could depend on the error code from the google command as well (I'm assuming it returns error if it failed to upload, but you should probably double check this).

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

A common misconception is that if wants a bracketed expression to evaluate, this is not true, if always takes a command and checks the error status; usually this command is [ which is an alias for test, which evaluates the expression. (And yes, I'd be surprised if there isn't an optimized shortcut to make it go faster inside bash, but conceptually it's still true).

Capturing output is done via backticks, like so

result=`command argument a b c`

or using $()

result=$(command argument a b c)

but it's probably better to use the error code in this case.

EDIT: You have a funny if thing in your function.. I didn't notice at first, but it can be avoided if you enable nullglob shell option (this will make ./*.mov to expand to the empty string, if there are no files). Also, quote that $f or it'll break if your file names contain spaces

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.

falstro
  • 34,597
  • 9
  • 72
  • 86
  • +1, Could use `$?`, I believe, for the error code used in the `if` as we've got a fairly large command. – Nick Apr 18 '11 at 10:45
  • 1
    @Nick, yes you could, and run a test command on if instead. It's slightly error prone though, as an echo in between would ruin it; so you would usually want to jump through a few hoops to be sure, like `google ..; result=$?; if [ $result -eq 0 ]; then ...` – falstro Apr 18 '11 at 10:47
  • @Nick; also note that if you put "then" on a separate line (which is a matter of style I suppose), you only add three characters to the initial command line `if google...`, followed by `then` on a separate line. I'm gonna edit it into that. – falstro Apr 18 '11 at 10:49
  • Thanks, roe for your awesome explanations! The google code does return an error code - I didn't know that before, but I just tried that and it works fine. Thanks again! – Patrick Apr 18 '11 at 11:35
  • Note that spacing is important.... there can't be a space between you variable name and the `=`. Couldn't figure out why it kept saying my variable was an invalid command! – mpen Jul 27 '11 at 01:41
4

I would call it, The command ... outputs a string. 'Return' is a keyword, and the return value is a number, where 0 means by convention success (0 errors) and a different value indicates an error code.

You grab the output by:

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

but will often see the inferior solution:

result=`cmd param1 param2`

inferior, because backticks are easily confused with apostrophes (depending on the font) and hard to nest, so don't use them.

From 'man bash':

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

and:

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.

The return value/exit code of the last command is gained through $?.

The keyword for the meaning you meant is command substitution. Again 'man bash':

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

          $(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).

   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.

   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.

user unknown
  • 35,537
  • 11
  • 75
  • 121
2

Use $()

variable=$(google youtube post --access unlisted --category Tech $f )
kurumi
  • 25,121
  • 5
  • 44
  • 52
2

If you are still getting output after > /dev/null then it's coming out on stderr, so standard backticks or $() won't work.

First, see if the return code indicates a problem: Examine $? after success and failure.

If it turns out the return code isn't sufficent, you can redirect the output:

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

2>&1 puts stderr on the stdout fd, before you redirect stdout to nothing.

Douglas Leeder
  • 52,368
  • 9
  • 94
  • 137
  • You are right, Douglas. It's coming out on stderr. I didn't expect this because in this case also success messages come out on stderr. For me that doesn't make much sense. Anyway, that's how it is. – Patrick Apr 18 '11 at 11:40
0

The answer to the question is to use the read command.

Sure all these other answers show ways to not do what the OP asked, but that really screws up the rest of us who searched for the OP's question.

Disclaimer: This is a duplicate answer

Here is how you do it...

Command:

# 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

Here is what it is doing and why it is important:

  1. Let's pretend that the series | of | commands is a very complicated series of piped commands.
  2. mystic_command is could accept stdin as the file, but not the option arg therefore it must come in as a variable**
  3. read takes stdin and places it into the variable $string
  4. Putting the read and the mystic_command into a "sub shell" via parenthesis is not necessary but makes it flow like a continuous pipe as if the 2 commands where in a separate script file.

** There is always an alternative, and in this case the alternative is ugly and unreadable:

mystic_command --opt "$(series | of | commands)" /path/to/file | handle_mystified_file
Community
  • 1
  • 1
Bruno Bronosky
  • 66,273
  • 12
  • 162
  • 149
0

You can assign it to a variable by using backticks:

CONTENT=`google youtube post --access unlisted --category Tech $f > /dev/null`
Nick
  • 6,967
  • 2
  • 34
  • 56
0

Example for access youtube

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 
  • You might consider adding a little bit of explanation or helpful comments to this answer in order to make it more useful to the poster. – Troy Alford Nov 08 '12 at 00:30