2012-03-09 2 views
2

Мое намерение состоит в том, чтобы вывести журнал рекурсивного wget в одну строку, 'status bar'-like. Поэтому я собрал этот трубопровод (мой wget вызов имеет немного больше вариантов, но я оставил тех, важно только для проблемы, описанной):Комплексный трубопровод bash работает в прыжках

wget -r -nv ftp://example.com 2>&1 | cut -c1-80 | xargs -I line echo -ne 'line\033[0K\r' 

Позвольте мне объяснить, что я имел в виду сделать. Может быть, с моей командой что-то не так.

  • -r означает «рекурсивная загрузка»;
  • -nv делает сообщения о каждой загрузке краткими, например: «time: URL -> local file»;
  • перенаправляет stderr на stdout, чтобы я мог работать с сообщениями через трубы;
  • | cut -c1-80 разрезает выходную линию до 80 символов. Иногда URL и локальное имя файла вместе образуют длинную строку, которая разбивает строку на 2 или более. И мне нужно, чтобы он вписывался в одну линию консоли. 80 стоит здесь, например. В моем сценарии я определяю ширину консоли с tput cols;
  • | xargs -I line echo -ne 'line\033[0K\r' печатает выходные данные предыдущей команды и добавляет два специальных символа: \033[OK - конец строки, который очищает остальную часть строки, если есть какие-либо символы, оставшиеся от выходов prevoius; и \r - возврат каретки, который устанавливает курсор в начало текущей строки.

Так что разыскиваемый поведение:

  1. wget загружает файл и пытается распечатать уведомление об этом на стандартный вывод
  2. cutсразу перехватывает вывод Wget и обрезает его до 80 символов
  3. xargs ловит обрезную линию и печатает ее немедленно со специальными символами

Поэтому я должен увидеть какую-то панель состояния, где отображается текущая загрузка.

Но! Все, что я вижу, ничего не происходит в течение 10-60 секунд, а затем все сообщения о загрузках, которые были сделаны за это время, печатаются примерно через 1 секунду. Они на самом деле печатали то, что я хотел, но очень быстро. Опять же, пауза, другая часть сообщений за 1 секунду и т. Д. Так что все хорошо, кроме сразу -ness.

Когда я удаляю часть xargs, сообщения отображаются мгновенно (но не в одной строке). Когда я удаляю cut звонок, они мгновенные, но иногда строка прерывается с некоторым действительно длинным URL-адресом. Если я удаляю только специальные символы от echo, вызов выводится по-прежнему «прыгающим», а не в одной строке.

Для того, чтобы воспроизвести это, вы можете заменить ftp://example.com на любой URL (HTTP тоже будет работать), который можно использовать для тестирования рекурсивной загрузки, то есть в случае FTP имеет много файлов и каталогов и в случай HTTP имеет много ссылок на страницы, у которых больше ссылок (не бойтесь, что он может попытаться загрузить весь интернет, beacuse -r имеет уровень рекурсии по умолчанию 5).Если вы не можете воспроизвести это, я полагаю, что это неправильно с моим дистрибутивом, пожалуйста, напишите об этом в разделе комментариев ниже.

P.S. Если вы знаете лучший способ организации строки состояния для wget, ваши комментарии очень приветствуются. Но я изучаю Баша и хочу знать, что вызывает такое странное поведение. Может быть, есть что-то о трубах или echo или xargs Не знаю. Поэтому возникает вопрос, почему этот трубопровод работает так, а не так, как я ожидал.

ответ

1

Проблема заключается в буферизации вывода, есть решения для этого: Turn off buffering in pipe

К сожалению, когда я пытаюсь применить их, я получаю xargs: unmatched double quote; by default quotes are special to xargs unless you use the -0 option.

Вы должны попробовать другой подход, я не думаю, что xargs является хорошим выбором для этой задачи, попробуйте AWK, Perl, Python, Ruby ...

+0

Спасибо! Теперь я знаю, что вызвало проблему (буферизацию) и как обойти ее (awk). И да, xargs действительно не подходит для манипуляций строк. – Hnatt

+1

Итак, в результате мой конвейер теперь выглядит так: 'wget -r -nv http://example.com 2> & 1 | awk -W interactive '{ORS = ""; print substr ($ 0,1,80) "\ 033 [0K \ r"} ''. '-W interactive' заставляет awks не выводить буфер, а' ORS = "" 'дает нам' print' без строк новой строки. – Hnatt

2

xargs собирает много строк ввода и вызывает команду (эхо в вашей ситуации) только один раз *. Добавьте '-L 1' к аргументам xargs и посмотрите, поможет ли это.

* xargs использует больше вызовов для команды, если командная строка будет слишком длинной, но как можно больше групп.

+0

Кажется разумным, и я не знаю, что о xargs, но: 1) это не помогает, вы пробовали его, и это сработало ?; 2) если я удалю '| вырезать трубы, работает, как и ожидалось, без сбора линий. – Hnatt

+0

В любом случае, спасибо за подсказку о опции '-L'. Я узнал, что он несколько несовместим с «-I». Вот что говорит человеческая страница. – Hnatt