echo '<h1>hello, world</h1>' | firefox
cat index.html | firefox
These commands don't work.
If firefox
can read stdin, I can send HTML to firefox
via a pipe.
Is it possible to make firefox
read stdin?
echo '<h1>hello, world</h1>' | firefox
cat index.html | firefox
These commands don't work.
If firefox
can read stdin, I can send HTML to firefox
via a pipe.
Is it possible to make firefox
read stdin?
You can use data URIs, like this:
echo '<h1>hello, world</h1>' |firefox "data:text/html;base64,$(base64 -w 0 <&0)"
&0
is the file descriptor for stdin, so it encodes stdin to base64
, then interpolates that into the data URI.
The same trick works for other browsers, too:
echo '<h1>hello, world</h1>' |chromium "data:text/html;base64,$(base64 -w 0 <&0)"
echo '<h1>hello, world</h1>' |opera "data:text/html;base64,$(base64 -w 0 <&0)"
If you want, you can put the second part in a bash script (I'll call it pipefox.sh
):
#!/bin/bash
firefox "data:text/html;base64,$(base64 -w 0 <&0)"
Now you can do:
echo '<h1>hello, world</h1>' |pipefox.sh
The short answer is, you're better off writing a temporary file and opening that. Getting pipes to work properly is more complicated and probably won't give you any extra advantages. That said, here's what I've found.
If your firefox
command is actually starting Firefox instead of talking with an already-running Firefox instance, you can do this:
echo '<h1>hello, world</h1>' | firefox /dev/fd/0
Which tells Firefox explicitly to read its standard input, which is where the pipe is putting its data. But if Firefox is already running, the firefox
command is just going to pass that name to the main Firefox process, which will read its own standard input, which probably won't give it anything and certainly isn't connected to your pipe.
Furthermore, when reading from a pipe, Firefox buffers things pretty heavily, so it's not going to update the page each time you give it a new line of HTML, if that's what you're going for. Try closing Firefox and running:
cat | firefox /dev/fd/0
(N.B. you do actually need the cat
here.) Paste some long lines into your shell window repeatedly until Firefox decides to update the page, and you can see how much data it takes. Now send an End-Of-File signal by hitting Ctrl+D on a new line, and watch Firefox update instantly. But then you can't add any more data.
So best is probably:
echo '<h1>hello, world</h1>' >my_temporary_file; firefox my_temporary_file
-new-instance
, so it becomes ... | firefox -new-instance /dev/fd/0
.
– rampion
Jan 23 '15 at 14:44
file:///dev/null
.
– aggregate1166877
May 04 '20 at 04:18
I found this:
bcat -- pipe to browser utility
... to install on Ubuntu Natty, I did:
sudo apt-get install rubygems1.8
sudo gem install bcat
# to call
ruby -rubygems /var/lib/gems/1.8/gems/bcat-0.6.2/bin/bcat
echo "<b>test</b>" | ruby -rubygems /var/lib/gems/1.8/gems/bcat-0.6.2/bin/bcat
I thought it works with its own browser - but running the above opened a new tab in an already running Firefox, pointing at a localhost address http://127.0.0.1:53718/btest
... With bcat
installation you can also do:
tail -f /var/log/syslog | ruby -rubygems /var/lib/gems/1.8/gems/bcat-0.6.2/bin/btee
... a tab will again open, but Firefox will keep showing the loading icon (and apparently would update the page when syslog updates).
The bcat
homepage also references the uzbl browser, which can apparently handle stdin - but for its own commands (should probably look into this more, though)
EDIT: As I needed something like this badly (mostly to view HTML tables with data generated on the fly (and my Firefox is getting really slow to be useful with bcat
), I tried with a custom solution. Since I use ReText, I already had installed python-qt4
and WebKit bindings (and dependencies) on my Ubuntu. So, I put together a Python/PyQt4/QWebKit script - which works like bcat
(not like btee
), but with its own browser window - called Qt4WebKit_singleinst_stdin.py
(or qwksisi
for short):
Basically, with the downloaded script (and dependencies) you can alias it in a bash
terminal like this:
$ alias qwksisi="python /path/to/Qt4WebKit_singleinst_stdin.py"
... and in one terminal (after aliasing), qwksisi
will raise the master browser window; while in another terminal (again after aliasing), one could do the following to obtain stdin data:
$ echo "<h1>Hello World</h1>" | qwksisi -
... as shown below:
Don't forget the -
at end to refer to stdin; otherwise a local filename can be used as last argument, as well.
Basically, the problem here is to solve:
As such, the same could be implemented in, say, Perl with Gtk bindings and WebKit (or other browser component). I wonder, though, if the XUL framework by Mozilla could be used to implement the same functionality - I guess in that case, one would work with the Firefox browser component.
Look what searching for 'browser stdin' turned up!, a nice little shell script:
#!/bin/sh
# read from stdin, write to a temp file, open the temp file in a browser, then delete it
tmpfile=$(tempfile); cat > $tmpfile; x-www-browser $tmpfile; rm $tmpfile
If you save this in stdin2www
, make it executable (chmod +x stdin2www
), your examples should work via cat index.html | ./stdin2www
. Just note that relative links, images, etc, will fail since the page that will be opened is something /tmp/
; more work would be needed to fix this.
You can use process substitution:
firefox <( echo '<h1>hello, world</h1>' )
firefox <( cat page_header.html contents.html footer.html )
firefox <( echo "<h1>Hello number "{1..23}"!</h1>" )
I wrote a python script to write stdin to a temporary file and then open the temporary file with Firefox.
#!/usr/bin/env python
import sys
import tempfile
import subprocess
with tempfile.NamedTemporaryFile() as f:
f.write(sys.stdin.read())
f.flush()
process = subprocess.Popen(['firefox', f.name])
process.wait()
You can run the below command from a shell script/terminal window.
Before launching Firefox (or any other browser), it will read from it's stdin the content to display upon opening.
If it is not HTML being sent, change the text/html
string in the below URL to whatever the file type is (for example, text/plain
or image/png
).
firefox "data:text/html;base64,$(base64)"
ffpipe
alias.note (Aug 2020): This no longer works to start a new instance in the latest Firefox, but still works with an existing instance open.
The data URI solutions given by snowball and luk3yx aren't working for me on GNU/Linux.
The following alias should work:
alias ffpipe='base64 -w0 <&0 | read -r x; firefox "data:text/html;base64,$x"'
eg.
echo '<h1>hello, world</h1>' | ffpipe
The page will only load once the pipe is closed (ie. end-of-file has been reached).
If incremental rendering of the piped content is required, you're better off using something like the previously-mentioned bcat
utility.
zsh: argument list too long:
– Raphael Ahrens
Oct 16 '20 at 08:45
Although this question is seven years old I am surprised that nobody proposed a solution serving the file through a web server. This is achieved with the following compact Python3 script. Save it as an executable file, say, browse.py:
#!/usr/bin/env python3
import sys, os, time, platform, signal
from subprocess import Popen
from http.server import HTTPServer, BaseHTTPRequestHandler
sys.stderr = open(os.devnull, 'w')
def timeoutHandler(signum, frame):
sys.exit("")
signal.signal(signal.SIGALRM, timeoutHandler)
signal.alarm(2)
html = sys.stdin.read()
port = int(sys.argv[1]) if len(sys.argv) > 1 else 8000
class Handler(BaseHTTPRequestHandler):
def _set_headers(self):
self.send_response(200)
self.send_header("content-type", "text/html")
self.end_headers()
def do_GET(self):
self._set_headers()
self.wfile.write(b = bytes(html, "utf-8"))
platform = platform.system().lower()
if platform.find("win") >= 0: command = "start"
elif platform.find("mac") >= 0 or platform.find("darwin") >= 0: command = "open"
else: command = "xdg-open"
p = Popen([command, "http://localhost:" + str(port) + "/"])
httpd = HTTPServer(("localhost", port), Handler)
httpd.serve_forever()
Then you can redirect standard input to the default browser:
./browser.py < somewebpage.html
echo "<html><body><h1>Hello</h1></body></html>" | browse.py
By default the server operates on port 8000, but that behavior can be changed with a command line argument:
./browser.py 9000 < website.html
I tested this script on Linux. It should handle other UNIX systems including MacOS out of the box. It is in principle even prepared for Windows (I don't have one for testing), but there it may be necessary to implement the timeout functionality differently.