Зачем обвязывать вывод команды docker-compose exec в grep? - PullRequest
0 голосов
/ 28 октября 2018

Я запускаю эту команду для запуска Drush, который по сути является PHP CLI для Drupal, в работающем контейнере:

docker-compose -f ../docker-compose.test.yml exec php scripts/bin/vendor/drush.phar -r public_html status-report

Вывод, если эта команда в порядке, это список состоянийинформация о конкретном экземпляре Drupal в контейнере.Я не буду вставлять его сюда, поскольку он длинный и не имеет значения.

Теперь давайте отфильтруем эту информацию, передав ее в grep:

docker-compose -f ../docker-compose.test.yml exec php scripts/bin/vendor/drush.phar -r public_html status-report | grep -e Warning -e Error

Результат:

Cro  Error     L 
Gra  Warning   P 
HTT  Error     F 
HTT  Warning   T 
Dru  Warning   N 
XML  Error     L

Что не так, похоже, что оно было разрезано на части, и большая часть его отсутствует.

Теперь, если мы отключим выделение псевдо-tty, добавив флаг -T:

docker-compose -f ../docker-compose.test.yml exec -T php scripts/bin/vendor/drush.phar -r public_html status-report | grep -e Warning -e Error

Вывод правильный:

Cron maintenance      Error     Last run 3 weeks 1 day ago                     
Gravatar              Warning   Potential issues                               
HTTP request status   Error     Fails                                          
HTTPRL - Non          Warning   This server does not handle hanging            
Drupal core update    Warning   No update data available                       
XML sitemap           Error     Last attempted generation on Tue, 04/18/2017 

Почему это так?

Бонусный вопрос, на который, вероятно, ответит ответ на предыдущий:Существуют ли какие-либо важные побочные эффекты использования -T?

Docker version 18.06.1-ce, build e68fc7a215
docker-compose version 1.22.0

ОБНОВЛЕНИЕ № 1:

Для упрощения я сохранил правильный вывод всего scripts/bin/vendor/drush.phar -r public_html status-report в файл test.txt и попробовал:

 docker-compose -f ../docker-compose.test.yml exec php cat test.txt | grep -e Warning -e Error

Интересно, что вывод правильный сейчас и без -T, поэтому он должен иметь отношение к Drush / php, хотяМне все еще интересно, что может быть причиной этого.

PHP 7.1.12 (cli) (built: Dec  1 2017 04:07:00) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies
    with Zend OPcache v7.1.12, Copyright (c) 1999-2017, by Zend Technologies
    with Xdebug v2.5.5, Copyright (c) 2002-2017, by Derick Rethans

Drush 8.1.17

ОБНОВЛЕНИЕ № 2:

Чтобы изолировать проблему дальшеЯ помещаю весь контент в файл PHP, то есть просто печатаю его, и после:

docker-compose -f ../docker-compose.test.yml exec php php php.php | grep -e Warning -e Error

Я получаю правильный вывод!

Так что это должно иметь какое-то отношение ккак Drush печатает свои сообщения, но я не понимаю, что это может быть.Это было бы довольно интересно, если бы мы могли это выяснить.

ОБНОВЛЕНИЕ № 3:

Хорошо, ребята, это настоящая магия.Проблема возникает также при запуске drush без каких-либо команд, чтобы вывести список всех доступных.Список команд нарушается, когда вывод передается по конвейеру, поэтому это можно проверить без реального экземпляра Drupal.

Теперь я хочу представить вам магию.

В drush, вывод для спискаиз доступных команд в commands/core/help.drush.php в функции drush_core_help().Есть этот призыв: drush_help_listing_print($command_categories); Я изучил это.Внутри находится вызов drush_print_table($rows, FALSE, array('name' => 20));, который отвечает за генерацию части выходного сигнала, который становится неработоспособным.

Так что внутри него я решил перехватить вывод перед самым последним вызовом drush_print(), добавивпросто file_put_contents('/var/www/html/data.txt', $output);

А теперь пришло время для меня совершенно волшебной части.

Когда я выполню:

docker-compose -f ../docker-compose.test.yml exec php scripts/bin/vendor/drush/drush -r public_html

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

 adminrole-update      Update the administrator role permissions.                                                                                                  
 elysia-cron           Run all cron tasks in all active modules for specified site using elysia cron system. This replaces the standard "core-cron" drush handler. 
 generate-redirects    Create redirects.                                                                                                                           
 libraries-download    Download library files of registered libraries.                                                                                             
 (ldl, lib-download)                                                                                                                                               
 libraries-list (lls,  Show a list of registered libraries.                                                                                                        
 lib-list)   

НО, если я выполню ту же команду , но выходные данные будут переданы по каналу или перенаправлены, например:

docker-compose -f ../docker-compose.test.yml exec php scripts/bin/vendor/drush/drush -r public_html | cat

ЧТО-ТО РАЗНОЕ БУДЕТ СОХРАНЕНО В ФАЙЛ:

 adminrole-update      U 
                       p 
                       d 
                       a 
                       t 
                       e 
                       t 
                       h 
                       e 
                       a 
                       d 
                       m 
                       i 
                       n 
                       i 
                       s 
                       t 
                       r 
                       a 
                       t 
                       o 
                       r 
                       r 
(and the rest of the broken output)

Таким образом, факт передачи / перенаправления вывода влияет на выполнение команды до того, кактруба / перенаправление фактически происходит.

Как это вообще возможно?O_o

1 Ответ

0 голосов
/ 29 октября 2018

Программа командной строки нередко меняет свое представление вывода в зависимости от того, является ли ее вывод терминалом или нет.Например, ls само по себе, без параметров, отображает файлы в столбчатом формате.Когда передано по конвейеру, выходные данные изменяются на список по одному файлу на строку.Это можно увидеть в исходном коде для GNU ls:

case LS_LS:
  /* This is for the 'ls' program.  */
  if (isatty (STDOUT_FILENO))
    {
      format = many_per_line;
      set_quoting_style (NULL, shell_escape_quoting_style);
      /* See description of qmark_funny_chars, above.  */
      qmark_funny_chars = true;
    }
  else
    {
      format = one_per_line;
      qmark_funny_chars = false;
    }
  break;

Вы можете эмулировать поведение ls | ... с явным аргументом ls -1, и это тоженередко: программы, которые неявно изменяют свое выходное представление, часто предоставляют способ явно задействовать это альтернативное представление.

Поддержка этого не просто соглашение: на самом деле это требование ls в POSIX :

Формат по умолчанию должен быть одинввод в строку на стандартный вывод;исключения относятся к терминалам или когда указана одна из опций -C, -m или -x.Если вывод на терминал, формат определяется реализацией.

Все это может показаться волшебным: как ls узнает, что у него есть канал , следующий за ним , поскольку онприходит до трубы?Ответ довольно прост: на самом деле оболочка анализирует всю командную строку, устанавливает каналы и , а затем разветвляет соответствующие программы с соответствующим вводом / выводом, подключенным к каналам.


Итак, какая часть команды выполняет альтернативное представление?Я подозреваю, что это взаимодействие между средой вашего exec и вычислением ширины столбца в drush.В моем локальном окружении drush help | ... не дает никаких необычных результатов.Вы могли бы попытаться передать по трубопроводу (или через) cat -vet, чтобы обнаружить какие-либо необычные символы в выводе.


Тем не менее, в отношении docker-compose конкретно: на основе этой темы ,Вы не единственный, кто столкнулся с этой или подобной проблемой.Я не тралял исходный код докера, но - вообще - не выделение псевдотерминала заставит другой конец действовать как неинтерактивная оболочка, что означает, что такие вещи как ваш .bash_profile не будут работать, и вы не будетебыть в состоянии прочитать стандартный ввод в команде запуска.Это может создать видимость вещей, которые не работают.

Поток, связанный выше, упоминает обходной путь этой формы:

docker exec -i $(docker-compose ...) < input-file

, что кажется разумным, учитывая значение -i, но этотакже кажется довольно запутанным для базовых сценариев.

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

...