What's up with this, how do I capture the output from my Gambit-C program?
$ gsi -e "(pp 'hello?)"
hello?
$ gsi -e "(pp 'hello?)" >asdf
hello?
$ gsi -e "(pp 'hello?)" 2>asdf
hello?
$ cat asdf
It should have put the output of the program into asdf, but it's empty!
Is there a compile-time or run-time option I can set to make it treat stdout like a normal unix program? (Preferably compile-time)
I am not familiar with pp, but you seem to want pretty-print:
$ gsi -e "(pretty-print 'hello?)" > test
$ cat test
hello?
$
Related
I'm guessing this has nothing to do with ack but more with bash:
Here we create file.txt containing the string foobar soack can find foobar in it:
> echo foobar > file.txt
> echo 'ack foobar file.txt' > ack.sh
> bash ack.sh
foobar
> bash < ack.sh
foobar
So far so good. But why doesn't ack find anything in it like this?
> cat ack.sh | bash
(no output)
or
> echo 'ack foobar file.txt' | bash
(no output)
Why doesn't ack find foobar in the last two cases?
Adding unbuffer (from expect) in front makes it work, which I don't understand:
> echo 'unbuffer ack foobar file.txt' | bash
foobar
Even stranger:
> cat ack2.sh
echo running
ack foobar file.txt
echo running again
unbuffer ack foobar file.txt
# Behaves as I'd expect
> bash ack2.sh
running
foobar
running again
foobar
# Strange output
> cat ack2.sh | bash
running
unbuffer ack foobar file.txt
What's up with this output? It echos unbuffer ack foobar file.txt but not running again? Huh?
ack gets confused because stdin is a pipe rather than a terminal. You need to pass the --nofilter option to force ack to treat stdin as a tty.
This:
# ack.sh
ack --nofilter foobar file.txt
works:
$ cat ack.sh | bash
foobar
If you ask me, that behaviour is quite unexpected. Probably it is expected when someone understand the concepts of ack which I do not atm. I would expect that ack doesn't look at stdin when filename arguments are passed to it.
Why does unbuffer "solve" the problem?
unbuffer, following it's man page, does not attempt to read from stdin:
Normally, unbuffer does not read from stdin. This simplifies use of
unbuffer in some situations. To use unbuffer in a pipeline, use the -p
flag. ...
Looks like ack tries to be too! smart about stdin here. If it is empty it does not read from stdin and looks at the filenames passed to it. Again, imo it would be correct to not look at stdin at all if filename arguments are present.
The big mismatch here is that ack was never intended to be used in shell scripts. It's meant as a command line tool for humans. That means that it makes some assumptions and optimizations for humans. For example, by default ack's output is different if it's going to a terminal vs. getting redirected in a pipe. There's also dangers in using ack in a shell script because its behavior can be affected by ackrc files and environment variables. If you're going to be using ack in a script, you should be using the --noenv flag. Better still, for shell scripts I'd use plain ol' grep.
What is the use case that brought up this problem?
I agree that this is a bug – ack could look at stdin, however in a NON BLOCKING way. It is a bug to hang over a pipe that's empty…
My question is similar to this one: How to detect if my shell script is running through a pipe?. The difference is that the script I’m working on is written in Ruby.
Let’s say I run:
./test.rb
I expect text on stdout with color, but
./test.rb | cat
I expect the color codes to be stripped out.
Use $stdout.isatty or more idiomatically, $stdout.tty?. I created a little test.rb file to demonstrate, contents:
puts $stdout.isatty
Results:
$ ruby test.rb
true
$ ruby test.rb | cat
false
Reference: https://ruby-doc.org/core/IO.html#method-i-isatty
Use IO#stat.pipe?.
IO#tty? returns true only on a TTY device.
Returns false for UNIX-style pipes (see "man 2 pipe").
$ echo "something" | ruby -e 'puts $stdin.stat.pipe?'
true
$ echo "something" | ruby -e 'puts $stdin.tty?'
false
$ ruby -e 'puts $stdin.tty?'
true
I want to pass command line options that start with a dash (- or --) to a Perl programm I am running with the -e flag:
$ perl -E 'say #ARGV' -foo
Unrecognized switch: -foo (-h will show valid options).
Passing arguments that don't start with a - obviously work:
$ perl -E 'say #ARGV' foo
foo
How do I properly escape those so the program reads them correctly?
I tried a bunch of variations like \-foo, \\-foo, '-foo', '\-foo', '\\-foo'. None of those work though some produce different messages. \\-foo actually runs and outputs \-foo.
You can use the -s, like:
perl -se 'print "got $some\n"' -- -some=SOME
the above prints:
got SOME
From the perlrun:
-s enables rudimentary switch parsing for switches on the command
line after the program name but before any
filename arguments (or before an argument of --). Any switch found there is removed from #ARGV and sets
the corresponding variable in the Perl program. The following program prints "1" if the program is
invoked with a -xyz switch, and "abc" if it is invoked with -xyz=abc.
#!/usr/bin/perl -s
if ($xyz) { print "$xyz\n" }
Do note that a switch like --help creates the variable "${-help}", which is not compliant with "use strict
"refs"". Also, when using this option on a script with warnings enabled you may get a lot of spurious
"used only once" warnings.
For the simple arg-passing use the --, like:
perl -E 'say "#ARGV"' -- -some -xxx -ddd
prints
-some -xxx -ddd
Just pass -- before the flags that are to go to the program, like so:
perl -e 'print join("/", #ARGV)' -- -foo bar
prints
-foo/bar
I thought this should be simple, but now that I'm trying it I can't figure it out. Did I take stupid pills this morning?
I have a command with output that is some variables that I want set. I thought I could use eval, but that apparently doesn't work.
Here's what I want to do:
$ ./foo
FOO=bar
BAR=baz
$ eval ./foo
$ echo $FOO
bar
How do I set those directly?
You need to evaluate the output of the script, not the string ./foo
$ eval $( ./foo )
What you try todo is sourcing the foo file into your shell. You can do that by invoking dot command and give your file as argument (the file does not have to be executable)
$ . ./foo
$ echo $FOO
bar
Can you explain the output of the following test script to me:
# prepare test data
echo "any content" > myfile
# set bash to inform me about the commands used
set -x
cat < myfile
output:
+cat
any content
Namely why does the line starting with + not show the "< myfile" bit?
How to force bash to do that. I need to inform the user of my script's doings as in:
mysql -uroot < the_new_file_with_a_telling_name.sql
and I can't.
EDIT: additional context: I use variables. Original code:
SQL_FILE=`ls -t $BACKUP_DIR/default_db* | head -n 1` # get latest db
mysql -uroot mydatabase < ${SQL_FILE}
-v won't expand variables and cat file.sql | mysql will produce two lines:
+mysql
+cat file.sql
so neither does the trick.
You could try set -v or set -o verbose instead which enables command echoing.
Example run on my machine:
[me#home]$ cat x.sh
echo "any content" > myfile
set -v
cat < myfile
[me#home]$ bash x.sh
cat < myfile
any content
The caveat here is that set -v simply echos the command literally and does not do any shell expansion or iterpolation. As pointed out by Jonathan in the comments, this can be a problem if the filename is defined in a variable (e.g. command < $somefile) making it difficult to identify what $somefile refers to.
The difference there is quite simple:
in the first case, you're using the program cat, and you're redirecting the contents of myfile to the standard input of cat. This means you're executing cat, and that's what bash shows you when you have set -x;
in a possible second case, you could use cat myfile, as pointed by #Jonathan Leffler, and you'd see +cat myfile, which is what you're executing: the program cat with the parameter myfile.
From man bash:
-x After expanding each simple command, for command, case command,
select command, or arithmetic for command, display the expanded
value of PS4, followed by the command and its expanded arguments or
associated word list.
As you can see, it simply displays the command line expanded, and its argument list -- redirections are neither part of the expanded command cat nor part of its argument list.
As pointed by #Shawn Chin, you may use set -v, which, as from man bash:
-v Print shell input lines as they are read.
Basically, that's the way bash works with its -x command. I checked on a Solaris 5.10 box, and the /bin/sh there (which is close to a genuine Bourne shell) also omits I/O redirection.
Given the command file (x3.sh):
echo "Hi" > Myfile
cat < Myfile
rm -f Myfile
The trace output on the Solaris machine was:
$ sh -x x3.sh
+ echo Hi
+ cat
Hi
+ rm -f Myfile
$ /bin/ksh -x x3.sh
+ echo Hi
+ 1> Myfile
+ cat
+ 0< Myfile
Hi
+ rm -f Myfile
$ bash -x x3.sh
+ echo Hi
+ cat
Hi
+ rm -f Myfile
$
Note that bash and sh (which are definitely different executables) produce the same output. The ksh output includes the I/O redirection information — score 1 for the Korn shell.
In this specific example, you can use:
cat myfile
to see the name of the file. In the general case, it is hard, but consider using ksh instead of bash to get the I/O redirection reported.