I am recoding printf and the behavior I get from my printf is slightly different from the real printf one because I work with strings (which are malloc) and real printf works with write functions.
When doing :
./a.out | cat -e
of :
#include <unistd.h>
int main()
{
printf(%c, 0);
return (0);
}
It is written ^# in the terminal
Whereas my function react the same without the pipe (cat -e) but with the pipe still prints nothing. Can you tell me how I can get my function write the "^#" when a | cat -e is used on it?
You are printing the character ascii value 0. It is a null value. When you are simply executing with ./a.out | cat or ./a.out it does not print anything. Because by default cat will not print non printable characters. But when you are using with cat -e, it is for printing the non-printable characters.
printf("%c",0);
From the man page of cat,
-e equivalent to -vE
-E, --show-ends
display $ at end of each line
-v, --show-nonprinting
use ^ and M- notation, except for LFD and TAB
Related
I have a .echo_colors file containing some variables for colors in the following format:
export red="\033[0;31m"
this works fine with echo -e, but i want to use this environment variables on a C code. I'm getting the variable via getenv and printing with printf:
#include <stdlib.h>
#include <stdio.h>
int main(){
char* color = getenv("red");
printf("%s", color);
printf("THIS SHOULD BE IN RED\n");
return 0;
}
with this program, i get
\033[0;31mTHIS SHOULD BE IN RED
The string is just being printed and not interpreted as a color code. printf("\033[0;31m") works and prints output in red as i want to. Any ideas for what to do to correct this problem?
Bash doesn't interpret \033 as "ESC" by default, as evident from hex-dumping the variable, but as "backslash, zero, three, three":
bash-3.2$ export red="\033[0;31m"
bash-3.2$ echo $red | xxd
00000000: 5c30 3333 5b30 3b33 316d 0a \033[0;31m.
You'll need to use a different Bash syntax to export the variable to have it interpret the escape sequence (instead of echo -e doing it):
export red=$'\033[0;31m'
i.e.
bash-3.2$ export red=$'\033[0;31m'
bash-3.2$ echo $red | xxd
00000000: 1b5b 303b 3331 6d0a .[0;31m.
Use ^[ (Control-left-bracket) in your shell script to key in the export command, as in
$ export red="<ctrl-[>[0;31m"
in your shell script, the ctrl-[ is actually the escape character (as typed from the terminal, it is possible that you need to escape it with Ctrl-V so it is not interpreted as an editing character, in that case, put a Ctrl-V in front of the escape char)
If you do
$ echo "<ctrl-[>[31mTHIS SHOULD BE IN RED"
THIS SHOULD BE IN RED (in red letters)
$ _
you will see the effect.
I have compiled the below c code which should send any input it receives in standard input to standard output. It works as expected in the following scenarios:
[user#host ~]$ ./my_program
test...
test...
^C
[user#host ~]$ echo "Hello" | ./my_program
Hello
[user#host ~]$ ./my_program < test.txt
Contents of test.txt ...
However, if I redirect the output of a shell command into my program like so:
[user#host ~]$ ./my_program <(echo "Hello")
It does not output anything and waits for input as if I started the program with just ./my_program
I expected an output of Hello and then the program to end. When I run the command cat <(echo "Hello") I get this expected result. What is causing the difference in behaviour between cat and my_program?
/* my_program.c */
#include <stdio.h>
int main()
{
int c = getchar();
while (c != EOF) {
putchar(c);
c = getchar();
}
return 0;
}
Posting Community Wiki because the question is caused by a typo and thus off-topic.
You're passing a filename associated with a pipeline with the output of echo "Hello" on your program's command line, not attaching it to stdin.
To attach it to stdin you need an extra < on the command line:
./my_program < <(echo "Hello")
It works with cat the other way because when cat is passed command-line arguments, it treats them as files to read from.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char buf[512];
fgets(buf, 512, stdin);
system("/bin/sh");
}
Compile with cc main.c
I would like a one-line command that makes this program run ls without it waiting for user input.
# This does not work - it prints nothing
(echo ; echo ls) | ./a.out
# This does work if you type ls manually
(echo ; cat) | ./a.out
I'm wondering:
Why doesn't the first example work?
What command would make the program run ls, without changing the source?
My question is shell and OS-agnostic but I would like it to work at least on bash 4.
Edit:
While testing out the answers, I found out that this works.
(python -c "print ''" ; echo ls) | ./a.out
Using strace:
$ (python -c "print ''" ; echo ls) | strace ./a.out
...
read(0, "\n", 4096)
...
This also works:
(echo ; sleep 0.1; echo ls) | ./a.out
It seems like the buffering is ignored. Is this due to the race condition?
strace shows what's going on:
$ ( echo; echo ls; ) | strace ./foo
[...]
read(0, "\nls\n", 4096) = 4
[...]
clone(child_stack=NULL, flags=CLONE_PARENT_SETTID|SIGCHLD, parent_tidptr=0x7ffdefc88b9c) = 9680
In other words, your program reads a whole 4096 byte buffer that includes both lines before it runs your shell. It's fine interactively, because by the time the read happens, there's only one line in the pipe buffer, so over-reading is not possible.
You instead need to stop reading after the first \n, and the only way to do that is to read byte by byte until you hit it. I don't know libc well enough to know if this kind of functionality is supported, but here it is with read directly:
#include <unistd.h>
#include <stdlib.h>
int main()
{
char buf[1];
while((read(0, buf, 1)) == 1 && buf[0] != '\n');
system("/bin/sh");
}
I have the following example program:
#include <stdio.h>
int
main(int argc, char ** argv){
char buf[100];
printf("Please enter your name: ");
fflush(stdout);
gets(buf);
printf("Hello \"%s\"\n", buf);
execve("/bin/sh", 0, 0);
}
I and when I run without any pipe it works as it should and returns a sh promt:
bash$ ./a.out
Please enter your name: warning: this program uses gets() which is unsafe.
testName
Hello "testName"
$ exit
bash$
But this does not work in a pipe, i think I know why that is, but I cannot figure out a solution. Example run bellow.
bash$ echo -e "testName\npwd" | ./a.out
Please enter your name: warning: this program uses gets() which is unsafe.
Hello "testName"
bash$
I figure this has something to do with the fact that gets empties stdin in such a way that /bin/sh receives a EOF and promtly quits without an error message.
But how do I get around this (without modifying the program, if possible, and not removing gets, if not) so that I get a promt even though I supply input through a pipe?
P.S. I am running this on a FreeBSD (4.8) machine D.S.
You can run your program without any modifications like this:
(echo -e 'testName\n'; cat ) | ./a.out
This way you ensure that your program's standard input doesn't end after what echo outputs. Instead, cat continues to supply input to your program. The source of that subsequent input is your terminal since this is where cat reads from.
Here's an example session:
bash-3.2$ cc stdin_shell.c
bash-3.2$ (echo -e 'testName\n'; cat ) | ./a.out
Please enter your name: warning: this program uses gets(), which is unsafe.
Hello "testName"
pwd
/home/user/stackoverflow/stdin_shell_question
ls -l
total 32
-rwxr-xr-x 1 user group 9024 Dec 14 18:53 a.out
-rw-r--r-- 1 user group 216 Dec 14 18:52 stdin_shell.c
ps -p $$
PID TTY TIME CMD
93759 ttys000 0:00.01 (sh)
exit
bash-3.2$
Note that because shell's standard input is not connected to a terminal, sh thinks it is not executed interactively and hence does not display the prompt. You can type your commands normally, though.
Using execve("/bin/sh", 0, 0); is cruel and unusual punishment for the shell. It gives it no arguments or environment at all - not even its own program name, nor even such mandatory environment variables as PATH or HOME.
Not 100% sure of this (the precise shell being used and the OS might throw these answers a bit; I believe that FreeBSD uses GNU bash by default as /bin/sh?), but
sh may be detecting that its input is not a tty.
or
Your version of sh might go into non-interactive mode like that also if called as sh, expecting login will prepend a - onto argv[0] for it. Setting up execve ("/bin/sh", { "-sh", NULL}, NULL) might convince it that it's being run as a login shell.
#include<stdio.h>
int main()
{
printf("He %c llo",65);
}
Output: He A llo
#include<stdio.h>
int main()
{
printf("He %c llo",13);
}
Output: llo. It doesnt print He.
I can understand that 65 is ascii value for A and hence A is printed in first case but why llo in second case.
Thanks
ASCII 13 is carriage return, which on some systems simply moves the cursor to the beginning of the line you were just on.
Further characters then wipe out the earlier text.
Man ascii:
Oct Dec Hex Char
015 13 0D CR '\r'
Character 13 is carriage return so it prints He then returns to the beginning of the line and prints the remining llo.
It's just being rendered strangely due to the nature of a carriage return*. You can see the characters that are output, by piping to another tool such as xxd:
$ gcc b.c && ./a.out | xxd
0000000: 4865 200d 206c 6c6f He . llo
$ gcc c.c && ./a.out | xxd
0000000: 4865 2041 206c 6c6f He A llo
* See Wikipedia:
On printers, teletypes, and computer terminals that were not capable of displaying graphics, the carriage return was used without moving to the next line to allow characters to be placed on top of existing characters to produce character graphics, underlines, and crossed out text.