Хотите проверить, успешно ли выполнена команда, перенаправив ее вывод в переменную

В настоящее время я пишу сценарий bash, который загружает видеофайлы на YouTube с помощью GoogleCL.

Поскольку я делаю эту загрузку в цикле (потому что может быть несколько видеофайлов), я хотел бы проверить, был ли успешно загружен каждый файл, прежде чем загружать следующий.

Команда google youtube post --access unlisted --category Tech $f (где $f представляет файл) выводит строку, которая сообщает мне, была ли загрузка успешной или нет.

Но я не знаю, как перенаправить эту «строку возврата» в переменную, чтобы проверить успехи.

Вот что у меня есть:

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

Кто-нибудь может мне помочь?


person Patrick    schedule 18.04.2011    source источник


Ответы (7)


Я предполагаю, что вы также можете зависеть от кода ошибки из команды google (я предполагаю, что она возвращает ошибку, если не удалось загрузить, но вам, вероятно, следует дважды проверить это).

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, но концептуально это все еще верно).

Захват вывода осуществляется с помощью обратных кавычек, например так

result=`command argument a b c`

или используя $()

result=$(command argument a b c)

но, вероятно, в этом случае лучше использовать код ошибки.

EDIT: У вас есть забавная штука if в вашей функции. Сначала я не заметил, но этого можно избежать, если вы включите опцию оболочки nullglob (это заставит ./*.mov расширяться до пустой строки , если файлов нет). Кроме того, укажите это $f, иначе он сломается, если ваши имена файлов содержат пробелы.

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

ХТН.

person falstro    schedule 18.04.2011
comment
+1, я думаю, можно было бы использовать $? для кода ошибки, используемого в if, поскольку у нас довольно большая команда. - person Nick; 18.04.2011
comment
@Ник, да, ты мог бы, и вместо этого запусти тестовую команду, если. Однако это немного подвержено ошибкам, так как эхо между ними разрушит его; так что вы обычно хотите прыгнуть через несколько обручей, чтобы быть уверенным, например google ..; result=$?; if [ $result -eq 0 ]; then ... - person falstro; 18.04.2011
comment
@Ник; также обратите внимание, что если вы поместите затем в отдельную строку (что, я полагаю, вопрос стиля), вы добавите только три символа в исходную командную строку if google..., а затем then в отдельной строке. Я собираюсь отредактировать это. - person falstro; 18.04.2011
comment
Спасибо, roe за ваши замечательные объяснения! Код Google возвращает код ошибки - я не знал этого раньше, но я только что попробовал, и он отлично работает. Еще раз спасибо! - person Patrick; 18.04.2011
comment
Обратите внимание, что интервал важен... между именем вашей переменной и = не может быть пробела. Не мог понять, почему он продолжал говорить, что моя переменная была недопустимой командой! - person mpen; 27.07.2011

Я бы назвал это The command ... outputs a string. 'Return' – это ключевое слово, а возвращаемое значение – число, где 0 означает, по соглашению, успех (0 ошибок), а другое значение указывает код ошибки.

Вы получаете результат:

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

но часто будет видеть худшее решение:

result=`cmd param1 param2`

уступает, потому что обратные кавычки легко спутать с апострофами (в зависимости от шрифта) и их трудно вложить друг в друга, поэтому не используйте их.

Из «мужского удара»:

Возвращаемым значением простой команды является ее статус выхода или 128+n, если команда завершается сигналом n.

и:

return [n]
Вызывает выход из функции с возвращаемым значением, заданным параметром n. Если n опущено, возвращается статус последней команды, выполненной в теле функции. Если используется вне функции, но во время выполнения скрипта . (источник), это приводит к тому, что оболочка прекращает выполнение этого сценария и возвращает либо n, либо статус выхода последней команды, выполненной в сценарии, в качестве статуса выхода сценария. Если используется вне функции, а не во время выполнения скрипта с помощью ., статус возврата будет ложным. Любая команда, связанная с ловушкой RETURN, выполняется до возобновления выполнения после функции или сценария.

Возвращаемое значение/код выхода последней команды получается через $?.

Ключевое слово для значения, которое вы имели в виду, это замена команды. Снова «мужской удар»:

Подстановка команд
Подстановка команд позволяет в выводе команды заменить имя команды. Есть две формы:

          $(command)
   or
          `command`

Bash выполняет расширение, выполняя команду и заменяя подстановку команды стандартным выводом команды с удалением всех завершающих символов новой строки. Встроенные символы новой строки не удаляются, но они могут быть удалены при разделении слов. Подстановка команды $(cat file) может быть заменена эквивалентной, но более быстрой командой $(‹ file).

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

Обратная косая черта сохраняет свое буквальное значение, за исключением случаев, когда за ними следуют $, ` или . Первая обратная кавычка, которой не предшествует обратная косая черта, завершает подстановку команды. При использовании формы $(command) все символы в скобках составляют команду; никто не лечится специально.

   Command substitutions may be nested.  To nest when using the

форма с обратными кавычками, экранируйте внутренние обратные кавычки с помощью обратной косой черты.

Если подстановка находится в двойных кавычках, разбиение на слова и раскрытие пути к результатам не выполняются.

person user unknown    schedule 18.04.2011

Если вы все еще получаете вывод после > /dev/null, то он выходит на stderr, поэтому стандартные обратные кавычки или $() не будут работать.

Сначала проверьте, указывает ли код возврата на наличие проблемы: Изучите $? после успеха и неудачи.

Если окажется, что кода возврата недостаточно, вы можете перенаправить вывод:

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

2>&1 помещает stderr в fd stdout, прежде чем вы перенаправите stdout в ничто.

person Douglas Leeder    schedule 18.04.2011
comment
Ты прав, Дуглас. Он выходит на stderr. Я не ожидал этого, потому что в этом случае также появляются сообщения об успешном выполнении на stderr. Для меня это не имеет особого смысла. Во всяком случае, это так. - person Patrick; 18.04.2011

Используйте 1_

variable=$(google youtube post --access unlisted --category Tech $f )
person kurumi    schedule 18.04.2011
comment
вы ничего не зафиксируете, потому что стандартный вывод перенаправляется. - person glenn jackman; 18.04.2011
comment
@Гленн. да, это наглое копирование и вставка без раздумий. - person kurumi; 18.04.2011

Вы можете назначить его переменной, используя обратные кавычки:

CONTENT=`google youtube post --access unlisted --category Tech $f > /dev/null`
person Nick    schedule 18.04.2011
comment
вы ничего не зафиксируете, потому что стандартный вывод перенаправляется. - person glenn jackman; 18.04.2011
comment
Ах да, вам понадобится 2>&1 для перенаправления stderr на stdout. - person Nick; 18.04.2011

Пример для доступа к ютубу

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 
person lamasnik    schedule 01.11.2011
comment
Вы можете рассмотреть возможность добавления небольшого объяснения или полезных комментариев к этому ответу, чтобы сделать его более полезным для автора. - person Troy Alford; 08.11.2012

Ответ на вопрос заключается в использовании команды read.

Конечно, все эти другие ответы показывают способы не делать то, что просил ОП, но это действительно портит впечатление от остальных из нас, которые искали вопрос ОП.

Отказ от ответственности: Это повторяющийся ответ

Вот как вы это делаете...

Команда:

# 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

Вот что он делает и почему это важно:

  1. Давайте представим, что series | of | commands представляет собой очень сложную серию передаваемых по конвейеру команд.
  2. mystic_command может принимать stdin в качестве файла, но не параметр arg, поэтому он должен быть указан как переменная**
  3. read берет стандартный ввод и помещает его в переменную $string
  4. Помещать read и mystic_command в «вложенную оболочку» через круглые скобки не обязательно, но это заставляет их течь как непрерывный канал, как если бы 2 команды находились в отдельном файле сценария.

** Всегда есть альтернатива, и в данном случае альтернатива уродлива и нечитаема:

mystic_command --opt "$(series | of | commands)" /path/to/file | handle_mystified_file
person Bruno Bronosky    schedule 02.03.2013