Why piping output of docker-compose exec to grep, breaks it? - php

I'm running this command to run Drush which is basically a PHP CLI for Drupal, in the running container:
docker-compose -f ../docker-compose.test.yml exec php scripts/bin/vendor/drush.phar -r public_html status-report
The output if this command is fine, it's the list of status information about a specific Drupal instance in the container. I won't be pasting it here as it's long, and irrelevant.
Now let's filter this information by piping it into 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
The result is:
Cro Error L
Gra Warning P
HTT Error F
HTT Warning T
Dru Warning N
XML Error L
Which is wrong, it looks like it has been cut to pieces, and most of it is missing.
Now, if we will disable allocating of pseudo-tty by adding -T flag:
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
The output is correct:
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
Why is that?
Bonus question, which probably will be answered by the answer to the previous one: Are there any important side effects of using -T?
Docker version 18.06.1-ce, build e68fc7a215
docker-compose version 1.22.0
UPDATE #1:
To simplify things I saved the correct output of the whole scripts/bin/vendor/drush.phar -r public_html status-report into a file test.txt and tried:
docker-compose -f ../docker-compose.test.yml exec php cat test.txt | grep -e Warning -e Error
Interestingly the output is correct now with and witout -T, so it has to have something to do with Drush/php, although I'm still interested what can be a cause of this.
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
UPDATE #2:
To isolate problem further I put all content in a PHP file, that is simply printing it, and after:
docker-compose -f ../docker-compose.test.yml exec php php php.php | grep -e Warning -e Error
I'm getting a correct output!
So it has to have something to do with how Drush is printing its messages, but I fail to see what it can be. That could be pretty interesting if we could figure this out.
UPDATE #3:
Ok guys, that's actual magic. The problem happens also with running drush without any commands, to list all available ones. The list of commands is broken when output is being piped, so this can be tested without actual Drupal instance.
Now I want to present you magic.
In drush, output for list of available commands in being generated in commands/core/help.drush.phpin function drush_core_help(). There is this call: drush_help_listing_print($command_categories); I looked into it. Inside is a call drush_print_table($rows, FALSE, array('name' => 20)); that is responsible for generating part of the output that's getting broken.
So inside of it, I decided to intercept the output, just before the last call to drush_print(), by adding simple file_put_contents('/var/www/html/data.txt', $output);
And now it's time for the absolutely magical part for me.
When I execute:
docker-compose -f ../docker-compose.test.yml exec php scripts/bin/vendor/drush/drush -r public_html
The last group of commands can be checked in this file, and in my case it's:
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)
BUT, if I execute the same command, but the output will be piped or redirected, so for example:
docker-compose -f ../docker-compose.test.yml exec php scripts/bin/vendor/drush/drush -r public_html | cat
SOMETHING DIFFERENT WILL BE SAVED INTO A FILE:
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)
So the fact of piping/redirecting of the output, influences execution of the command, before the pipe/redirection actually happens.
How is that even possible? O_o

It's not uncommon for a command-line program to change its output presentation based on whether its output is a terminal, or not. For example, ls by itself, with no options, displays files in a columnar format. When piped, the output changes to a list of one-file-per-line. You can see this in the 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;
You can emulate the behavior of ls | ... with the explicit argument ls -1, and this too is not uncommon: programs that implicitly change their output presentation often provide a way to explicitly engage that alternate presentation.
Support for this isn't just a convention: it's actually a requirement for 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.
This all may seem magical: how does ls know it's got a pipe following it since it comes before the pipe? The answer is quite simple, really: the shell parses the whole command line, sets up the pipes, and then forks the respective programs with the input/output wired to pipes appropriately.
So, what part of the command is doing the alternate presentation? I suspect it's an interaction between the environment of your exec and the column width calculation in drush. On my local environment, drush help | ... doesn't produce any unusual results. You might try piping to (or through) cat -vet to discover any unusual characters in the output.
That said, regarding docker-compose specifically: based on this thread, you're not the only one who has encountered this or a similar issue. I've not trawled the docker source code, but - generally - not allocating a pseudo-tty will make the other end act like a non-interactive shell, which means things like your .bash_profile won't run and you won't be able to read stdin in the run command. This can give the appearance of things not working.
The thread linked above mentions a work around of this form:
docker exec -i $(docker-compose ...) < input-file
which seems reasonable given the meaning of -i, but it also seems rather convoluted for basic scripting.
The fact that -T makes it work for you suggests to me that you have something in your .bash_profile (or similar login-shell-specific start up file) that's changing certain values (maybe COLUMNS) or altering the values in such a way as to have the observed deleterious effect. You might try removing everything from those files, then adding them back to see if any particular one causes the issue.

I didn't read that very detailed question, but from glancing over it, I'd say the -T option to the exec subcommand is essential if you want to process stdout and stderr in the environment where you execute docker-compose.

Related

Why is PATH on mac not working? [duplicate]

Can anyone explain how python 2.6 could be getting run by default on my machine? It looks like python points to 2.7, so it seems like which isn't giving me correct information.
~> python --version
Python 2.6.5
~> which python
/opt/local/bin/python
~> /opt/local/bin/python --version
Python 2.7.2
~> ls -l /opt/local/bin/python
lrwxr-xr-x 1 root admin 24 12 Oct 16:02 /opt/local/bin/python -> /opt/local/bin/python2.7
When I generate an error, I see what's really getting run. Why could this be?
~> python -error-making-argument
Unknown option: -e
usage: /Library/Frameworks/Python.framework/Versions/2.6/Resources/Python.app/Contents/MacOS/Python [option] ... [-c cmd | -m mod | file | -] [arg] ...
Try `python -h' for more information.
And how can I correct it?
From suggestions in comments:
~> alias
alias cp='cp -i'
alias gcc='gcc -Wall'
~> type python
python is /opt/local/bin/python
Bash uses an internal hash table to optimize $PATH lookups. When you install a new program with the same name as an existing program (python in this case) earlier in your $PATH, Bash doesn't know about it and continues to use the old one. The which executable does a full $PATH search and prints out the intended result.
To fix this, run the command hash -d python. This will delete python from Bash's hash table and force it to do a full $PATH search the next time you invoke it. Alternatively, you can also run hash -r to clear out the hash table entirely.
The type builtin will tell you how a given command will be interpreted. If it says that a command is hashed, that means that Bash is going to skip the $PATH search for the executable.
I just checked my .bash_profile, and it contained the following:
# Setting PATH for MacPython 2.6
# The orginal version is saved in .bash_profile.pysave
PATH="/Library/Frameworks/Python.framework/Versions/2.6/bin:/usr/local/git/bin:${PATH}"
export PATH
Commenting this out has fixed my problem.
If someone can tell me why which and type still gave incorrect answers, I'd be very grateful, and will give them a check-mark!
Thanks for all your guidance!

PHP to exec casperjs/phantomjs script

I'm having trouble using PHP to execute a casperjs script:
<?php
putenv("PHANTOMJS_EXECUTABLE=/usr/local/bin/phantomjs");
var_dump(exec("echo \$PATH"));
exec("/usr/local/bin/casperjs hello.js website.com 2>&1",$output);
var_dump($output);
Which results in the following output:
string(43) "/usr/gnu/bin:/usr/local/bin:/bin:/usr/bin:."
array(1) {
[0]=>
string(36) "env: node: No such file or directory"
}
The only stackoverflow posts I could find hinted that there's a problem with my paths, and that maybe the PHP user can't access what it needs.
I have also tried the following: sudo ln -s /usr/bin/nodejs /usr/bin/node
Does anyone know what I would need to do or change for this error to resolve?
Thanks
My guess is you have something, somewhere, that assumes node is installed.
First, are you running php from the commandline? I.e. as php test.php in a bash shell. If so, you can run the commands, below, as they are. If through a web server the environment can be different. I'd start with making a phpinfo(); script, and then run the troubleshooting commands through shell_exec() commands. But, as that is a pain, I'd get it working from the commandline first, and only mess around with this if the behaviour is different when run through a web server. (BTW, if you are running from a cron job, again, the environment can be slightly different. But only worry about this if it works from commandline but does not work from cron.)
Troubleshoot hello.js
The easy one. Make sure your script does not refer to node anywhere. Also remember you cannot use node modules. So look for require() commands that should not be there.
Troubleshoot your bash shell
Run printenv | grep -i node to see if anything is there. But when PHP runs a shell command, some other files get run too. So check what is in /etc/profile and ~/.bash_profile . Also check /etc/profile.d/, /etc/bashrc and ~/.bashrc. You're basically looking for anything that mentions node.
Troubleshoot phantomjs/casperjs
How did you install phantomjs and casperjs? Are the actual binaries under /usr/local/bin, or symlinks, or are they bash scripts to the . E.g. on my machine:
cd /usr/local/bin
ls -l casperjs phantomjs
gives:
lrwxrwxrwx 1 darren darren 36 Apr 29 2014 casperjs -> /usr/local/src/casperjs/bin/casperjs
lrwxrwxrwx 1 darren darren 57 Apr 29 2014 phantomjs -> /usr/local/src/phantomjs-1.9.7-linux-x86_64/bin/phantomjs
And then to check each file:
head /usr/local/src/casperjs/bin/casperjs
head /usr/local/src/phantomjs-1.9.7-linux-x86_64/bin/phantomjs
The first tells me casper is actually a python script #!/usr/bin/env python, while the second fills the screen with junk, telling me it is a binary executable.

Initialising PHP interactive

I often find PHP's interactive mode—php -a—very useful, but it would be far more useful if I could start it and have a few commands executed right away to initialize my environment. Things like run the autoloader, set up a few use shortcuts for namespaces, etc.
Here's an example:
include "../../autoloader.php";
use App/Foo/Bar as Bar;
I thought maybe I could just add these lines to a text file initialize.txt and then start the interactive mode with php -a < initialize.txt, but that didn't work.
How can I do this?
As Tomas Creemers mentioned, you have to use auto_prepend_file PHP flag to auto-require a file. For example:
<?php
# foo.php
function bar() { print "Bar.\n"; }
You can load the PHP interpreter like this:
php -d auto_prepend_file=$PWD/foo.php -a
Session:
Interactive shell
php > bar();
Bar.
Or you can include file manually:
php -a
Session:
Interactive shell
php > include 'foo.php';
php > bar();
Bar.
You can use the php.ini setting auto_prepend_file to specify a file that should always be executed before the actual file.
According to the documentation on interactive shell, this setting is also active there.
Assuming you don't want to do this initialization for every single time you start PHP, I would suggest creating a copy of your php.ini file (call it 'php.ini-interactive', for example) and specify that configuration file with the -c option: php -c /path/to/php.ini-interactive -a.
According to a comment (by "Ryan P") on the documentation page for PHP interactive shell, php -a does not always do the same thing:
Interactive Shell and Interactive Mode are not the same thing, despite
the similar names and functionality.
If you type 'php -a' and get a response of 'Interactive Shell'
followed by a 'php>' prompt, you have interactive shell available (PHP
was compiled with readline support). If instead you get a response of
'Interactive mode enabled', you DO NOT have interactive shell
available and this article does not apply to you.
You can also check 'php -m' and see if readline is listed in the
output - if not, you don't have interactive shell.
Interactive mode is essentially like running php with stdin as the
file input. You just type code, and when you're done (Ctrl-D), php
executes whatever you typed as if it were a normal PHP (PHTML) file -
hence you start in interactive mode with '<?php' in order to execute
code.
I do not have a copy of PHP with interactive shell available. I only have interactive mode, apparently. I have tested (see below) and can confirm that files configured with auto_prepend_file are executed in interactive mode. However, you may want to reconsider using it if you get the same symptoms as me:
cat /tmp/prepend.php
Output:
<?php
echo 'cookies are people too!';
Further:
grep auto_prepend_file /etc/php5/cli/php.ini
Output:
auto_prepend_file =
grep auto_prepend_file /etc/php5/cli/php.ini-interactive
Output:
auto_prepend_file = /tmp/prepend.php
php -a
Session:
Interactive mode enabled
php -c /etc/php5/cli/php.ini-interactive -a
Output:
Interactive mode enabled
cookies are people too!
Segmentation fault
php --version
Output:
PHP 5.4.4-14+deb7u2 (cli) (built: Jun 5 2013 07:56:44)
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2012 Zend Technologies
(Keyboard input in that last interactive mode run is only a return followed by Ctrl + D.)

Windows CMD.exe "The system cannot find the path specified."

Solved by restoring Windows to previous state
The message (The system cannot find the path specified.) shows...
1) When i open new CMD (Win+R => cmd). It starts with introduction. (on line 3)
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
The system cannot find the path specified.
C:\Users\ViliamKopecky>
2) When i execute some command like cmd /C dir (or cmd /C php -v or whatever) (on line 2)
C:\Users\ViliamKopecky>cmd /C dir
The system cannot find the path specified.
Volume in drive C is Windows7_OS
Volume Serial Number is 8230-1246
...
C:\Windows\System32>cmd /C php -v
The system cannot find the path specified.
PHP 5.4.8 (cli) (built: Oct 16 2012 22:30:23)
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2012 Zend Technologies
3) (the most annoying) when i run exec function from PHP or Node.js or probably any scripting lang. (which are probably runned from inside as cmd /C <command>)
The message does not show...
1) when i execute the command right from the cmd (or mingw, ...)
C:\Users\ViliamKopecky>dir
Volume in drive C is Windows7_OS
Volume Serial Number is 8230-1246
Directory of C:\Users\ViliamKopecky
Let's start with simple command from cmd.
php -r "exec('dir', $stdout, $stderr); print(implode(\"\n\", $stdout), $stderr);"
and the result is like this (the directory test is empty - that is correct):
E:\test>php -r "exec('dir', $stdout, $stderr); print(implode(\"\n\", $stdout), $stderr);"
The system cannot find the path specified.
Volume in drive E is www
Volume Serial Number is 0C99-95EC
Directory of E:\test
09.11.2012 22:42 <DIR> .
09.11.2012 22:42 <DIR> ..
0 File(s) 0 bytes
2 Dir(s) 13 495 296 000 bytes free
int(1)
Which shows that the command dir has is executed from php correctly. Only thing thats wrong is the second line - The system cannot find the path specified. - that should not be there.
This message is output by exec from PHP (and also from Node.js as require('child_process').exec("dir", function(err, stdout, stderr) {console.log(stderr)});)
When I execute command right from cmd (or mingw, etc.) it executes correctly without the message. Environment variable PATH seem ok. Problem is just executing from script environment through exec functions.
How to get rid of that annoying message? Thanks
The problem is that some program has been set to autorun when you run cmd.exe.
In my case it was ANSICON that was installed... and then I moved the file without properly uninstalling.
I found a solution in this blog post:
http://carol-nichols.com/2011/03/17/the-system-cannot-find-the-path-specified/
The short version is to find
HKCU\Software\Microsoft\Command Processor\AutoRun
and clear the value.
This message can mean a path in the PATH enviromental variable doesn't exist.
The following PowerShell command will print missing paths.
($env:path).Trim(";").Split(";") | ? {-not (test-path $_)}
e.g.
> ($env:path).Trim(";").Split(";") | ? {-not (test-path $_)}
C:\Program Files\CMake\bin
C:\Program Files\SDCC\bin
C:\Users\wjbr\AppData\Local\Programs\Microsoft VS Code\bin
References
http://carol-nichols.com/2011/03/17/the-system-cannot-find-the-path-specified/
https://javarevisited.blogspot.com/2017/01/the-system-cannot-find-path-specified-error-in-command-prompt.html
This actually looks like a startup error with PHP, not with your code. Does
php -r "echo 1;"
also throw the same error? If so, your php.ini file or an include may be pathed incorrectly.
php -i
should give you more info.
I think you should try this out ! I had the same issue and solved it like this :
ok type : cd\windows\system32
After that you will see this: System32/:
Type what you want (ex:ipconfig):
System32: ipconfig
Then that should do it !
:)

PHP function is_executable returns false even though the file is definitely executable

I'm using PHP 5.3.
Using getfacl the files permissions are:
user::rwx
group::r-x
other::r-x
I also am having problems using PHP's Program execution Functions, http://www.php.net/manual/en/ref.exec.php
The program in question is wkhtmltopdf and I have it in my /usr/bin directory.
I have the convert program in my /usr/bin directory with the exact same permissions and the is_executable function returns true.
For me the answer was to create a policy module to allow wkhtmltopdf to run without disabling SELinux:
sudo su - (run as root to make the next steps simpler)
tail -F /var/log/audit.log | grep wkhtml > wkhtml.audit (leave
this running and continue to next step)
try to load your web page that attempts to create a pdf, it will fail as before but now we are
logging.
CTRL+C to stop the process from step 2 (can skip to 7 if in
a hurry, but it's strongly suggested you use these review steps before making
selinux exceptions permanent!)
cat wkhtml.audit | audit2allow -m
wkhtmltopdf > wkhtmltopdf.te
review the wkhtmltopdf.te file to
make sure new rules will be sensible. you will probably see "allow
httpd_t self:process execmem" and possibly "allow httpd_t var_t:file
read" depending on your setup
cat wkhtml.audit | audit2allow -M
wkhtmltopdf
semodule -i wkhtmltopdf.pp (might take a minute,
be patient)
You should now be able to load the pdf-creating page without error. If not, we have likely fixed one problem and arrived at another--might need to repeat steps. Tail to wkhtml.audit2 this time and cat it with the original when making a new module (or else you'll be undoing first fix!):
tail -F ... > wkhtml.audit2
if audit2 is empty, there is a non-selinux problem. otherwise:
cat wkhtml.audit wkhtml.audit2 | audit2allow ...
After some research I solved this. The problem was selinux policies standing in the way. I used the Security Context from /usr/bin/convert and used the chcon command to apply the same security context to /usr/bin/wkhtmltopdf

Categories