问题
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?
回答1:
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.
回答2:
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.
回答3:
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.
回答4:
Use $()
variable=$(google youtube post --access unlisted --category Tech $f )
回答5:
You can assign it to a variable by using backticks:
CONTENT=`google youtube post --access unlisted --category Tech $f > /dev/null`
回答6:
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
回答7:
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:
- Let's pretend that the
series | of | commands
is a very complicated series of piped commands. mystic_command
is could accept stdin as the file, but not the option arg therefore it must come in as a variable**read
takes stdin and places it into the variable$string
- Putting the
read
and themystic_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
来源:https://stackoverflow.com/questions/5701653/want-to-check-whether-a-command-succeeded-by-redirecting-its-output-to-a-variabl