Комплексный баш-трубопровод работает в прыжках - PullRequest
2 голосов
/ 09 марта 2012

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

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";
  • &2>1 перенаправляет stderr на стандартный вывод, чтобы я мог работать с сообщениями по каналам;
  • | 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 секунду и так далее. Так что все в порядке, кроме сразу -несс.

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

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

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

Ответы [ 2 ]

2 голосов
/ 09 марта 2012

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

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

1 голос
/ 09 марта 2012

Проблема заключается в буферизации вывода, для этого есть следующие решения: Отключить буферизацию в конвейере

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

Вы должны попробовать другой подход, я не думаю, что xargs - хороший выбор для этой задачи, попробуйте awk, perl, python, ruby ​​...

...