jjzjj

php - 为什么将 docker-compose exec 的输出管道输出到 grep,会破坏它?

coder 2024-04-19 原文

我正在运行此命令以在正在运行的容器中运行 Drush,它基本上是用于 Drupal 的 PHP CLI:

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

哪个不对,好像被剪成碎片了,大部分都不见了。

现在,如果我们要通过添加 -T 标志来禁用伪 tty 的分配:

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

最佳答案

命令行程序根据其输出是否为终端来更改其输出表示的情况并不少见。例如,ls 本身没有任何选项,以柱状格式显示文件。通过管道传输时,输出更改为每行一个文件的列表。你可以在 source code for 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 in POSIX 的要求:

The default format shall be to list one entry per line to standard output; the exceptions are to terminals or when one of the -C, -m, or -x options is specified. If the output is to a terminal, the format is implementation-defined.

这一切看起来很神奇:ls 如何知道它有一个管道之后,因为它在之前 管道?答案非常简单,真的:shell 解析整个命令行,设置管道,然后派生相应的程序,并将输入/输出适本地连接到管道。


那么,命令的哪一部分正在执行备用演示文稿?我怀疑这是您的 exec 环境与 column width calculation 之间的交互匆忙中。在我的本地环境中,drush help | ... 不会产生任何异常结果。您可以尝试通过管道传输到(或通过)cat -vet 以发现输出中的任何异常字符。


也就是说,具体关于 docker-compose:基于 this thread ,您不是唯一遇到此问题或类似问题的人。我没有拖网 docker 源代码,但是 - 通常 - 不分配伪 tty 会使另一端像非交互式 shell 一样工作,这意味着你的 .bash_profile 不会运行,您将无法在运行命令中读取标准输入。这会使事情看起来不正常。

上面链接的线程提到了这种形式的解决方法:

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

考虑到 -i 的含义,这似乎是合理的,但对于基本脚本而言,这似乎也相当复杂。

-T 使它为你工作的事实向我表明你的 .bash_profile (或类似的特定于登录 shell 的启动文件)中有一些东西改变某些值(可能是 COLUMNS)或改变值以产生观察到的有害影响。您可以尝试从这些文件中删除所有内容,然后将它们添加回去,看看是否有任何特定文件导致了问题。

关于php - 为什么将 docker-compose exec 的输出管道输出到 grep,会破坏它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53027036/

有关php - 为什么将 docker-compose exec 的输出管道输出到 grep,会破坏它?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  3. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  4. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  5. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  6. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  7. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

    我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

  8. ruby - ruby 中的 TOPLEVEL_BINDING 是什么? - 2

    它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput

  9. ruby - Infinity 和 NaN 的类型是什么? - 2

    我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

  10. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

随机推荐