122

I've written a tiny program in Ansi C on Windows first, and I compiled it on Ubuntu with the built-in GCC now.

The program is simple:

  • read the line from console with scanf().
  • Analyze the string and calculate.

But something weird happens. When I try to move the cursor, it prints four characters:

  • pressing Up prints "^[[A"
  • pressing Dn prints "^[[B"
  • pressing Rt prints "^[[C"
  • pressing Lt prints "^[[D"

  • How can this be avoided?

  • Why does it print these 4 characters instead of moving the cursor?

Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
Kevin Dong
  • 5,001
  • 9
  • 29
  • 62
  • 2
    Special characters like ^U and Backspace will work because the keyboard driver handles those. But the arrow key behavior you're used to is programmed into the shell. When you write your own program, you have to handle it yourself, or you could install `rlwrap` and run your program as `rlwrap my_prog` and it will do what you expect. The characters you see are the escape sequences generated by those key presses. – lurker Jan 27 '14 at 15:02
  • 1
    Those are the traditional ANSI escape sequences which represent those cursor keys. See http://stackoverflow.com/questions/4130048/recognizing-arrow-keys-with-stdin – keshlam Jan 27 '14 at 15:05
  • 2
    [This answer](https://unix.stackexchange.com/a/444270/87749) on unix.stackexchange may help, it helped me understand the issue. – A1rPun May 26 '21 at 21:30
  • In Ubuntu if yout just need a posix shell, you can use `set -o posix` or `--posix` to force the default shell into compliance. Dash is not compiled for interactive use. – Ray Foss Jun 10 '21 at 18:08
  • Have two Q&As been erroneously merged here? Half the answers seem to be answering some completely different question to do with shells, not with someone writing a C program that calls `scanf()`, and yet almost 70 people across 2 years think that they are somehow good answers when they won't make the tiniest bit of difference to the situation presented. – JdeBP Jun 06 '23 at 20:54

9 Answers9

45

Because that's what the keyboard actually sends to the PC (more precisely, what the terminal prints for what it actually receives from the keyboard). bash for example gets those values, deciphers them and understands that you want to move around, so it will either move the cursor (in case of left/right) or use its history to fetch previous commands (up/down). So you can't expect your program to magically support arrow keys.

However, reading from standard input from the terminal already supports left/right arrow keys (I believe, but I'm not in Linux right now to test and make sure). So my guess is that there is another issue interfering. One possible cause could be that one of your modifier keys is stuck? Perhaps ALT, CTRL or SUPER?

Shahbaz
  • 46,337
  • 19
  • 116
  • 182
  • 2
    When I press arrow keys in terminal, it'll move the cursor, but when reading input from buffer with scanf(), it can't. – Kevin Dong Jan 27 '14 at 15:10
  • @KevinDongNaiJia, it could be that `bash` detects the modifier and ignores them. Unfortunately, right now I'm in Windows, so I can't really tell. Just to be sure, you using the normal `gnome-terminal` and have not modified any settings, either of the terminal or of the keyboard (in Ubuntu settings)? – Shahbaz Jan 27 '14 at 15:16
  • Yes, I tested it in normal `gnome-terminal` without any settings. I just used Ubuntu in the second day. ;-) – Kevin Dong Jan 27 '14 at 15:22
  • What is your keyboard's layout? Try changing its layout to "Enlish (US)" and see if the problem persists. – Shahbaz Jan 27 '14 at 15:28
  • Nothing changed when using "English (US)" keyboard layout. And I tried to execute it in tty1~tty6, this problem still happened. – Kevin Dong Jan 27 '14 at 15:36
  • This is really weird, what is your keyboard brand/model? Does this happen in the terminal of Windows if you have one? What if you attach this keyboard to someone else's computer with Ubuntu? Do you still see the same behavior? – Shahbaz Jan 27 '14 at 16:02
  • I use notebook, so the keyboard is built-in. Then I used USB-keyboard (English (US) Layout), but the problem still existed. Last, I tested it in other Ubuntu derivative, **K**ubuntu, and this problem didn't solve. – Kevin Dong Jan 28 '14 at 01:18
  • 1
    This very likely some incompatibility between something in your laptop and Ubuntu (you can thank Microsoft's monopoly for that). Try asking on askubuntu.com, perhaps someone there has experienced something like that. Make sure to include the laptop brand and model – Shahbaz Jan 28 '14 at 08:23
  • 11
    Actually, the problem seems to be the **mode of the terminal**: The terminal has different modes, like either directly sending each character to the process, or aggregating a line until the user presses enter, or displaying stuff with history scroll-back as opposed to `vim` style full-screen mode. There is a lot of stuff that's going on, and I don't have the time right now to look up the details (which is why I'm not posting an answer myself). Anyway, when you see `^[[A` appear on the screen, that's the escape sequence sent to represent the up arrow, and nothing interpreted it as such. – cmaster - reinstate monica Aug 10 '18 at 11:07
  • The symbols ^[[A are a common problem (exactly these chars) when trying to use the line-edit and the shell mismatches. It is definitely not a problem about stuck keys such as ALT. answer from cmaster looks good. – Blindleistung Nov 18 '20 at 14:21
38

For those who are coming from the osx (mac) try changing the shells to bash

Terminal -> Preferences -> Shells open with -> [select] Command (complete path)

then paste

/bin/bash

Neuron
  • 5,141
  • 5
  • 38
  • 59
KhaledMohamedP
  • 5,000
  • 3
  • 28
  • 26
  • I was trying to exec into a docker instance on OSX (using Kitematic). This worked a treat, thank you. The Kitematic preferences let you set the shell to `bash`. – chichilatte Jul 27 '18 at 09:58
33

This might be because the user account is created in shell. You can change it to bash by two ways.

Permament solution is -

sudo chsh -s /bin/bash ${username}

To get this solution working you will have to logout and login

Temporary solution is everytime when you login into the ubuntu server type bash and hit return.

Sumith08
  • 582
  • 6
  • 16
5

If it's under a docker container, run /bin/bash . This helped me solve the problem.

shark.tar.gz
  • 61
  • 1
  • 2
2

Additionally to what Shahbaz mentioned, I realized that pressing enter (thus sending an empty command) can fix the problem. This is usually necessary after using CTRLC to cancel a command.

Nosferath
  • 21
  • 3
0

On MacOS Terminal for me was enough to uncheck "Scroll alternate screen" for the issue to disappear. See screenshot of the preferences below.enter image description here

Ivan Carosati
  • 355
  • 4
  • 13
0

You can (re)bind keys. Add this at the bottom of your .profile, .zshrc or whatever shell config you have.

bindkey -e
bindkey '\e\e[C' forward-word
bindkey '\e\e[D' backward-word
Jos
  • 1,387
  • 1
  • 13
  • 27
0

Installed rlfe

rlfe - "cook" input lines for other programs using readline

Worked for me on Pop!_OS / Ubuntu using bash.

sudo apt-get install rlfe

And the problem was just fixed, don't know how, but it works.

EDIT: Apparently rlfe can cause some minor bugs and you also have to run rlfe command every time you open the terminal, which is obviously not really convenient. So my solution was to just append rlfe to ~/.bashrc. When you open a new terminal - nothing happens, you just have to ^C and it'll be fine. Even though it is an easy solution to the problem, I don't think it's good. What if you writing a program for someone? Do they really have to do that rlfe fix? Solution is not user-friendly, and you probably don't wanna put rlfe at ~/.bashrc for the end user, because the command always has to be at the end, otherwise bash will just ignore everything that goes after -> you will break end user's .bashrc. So you should probably go with rlwrap or fix the problem programmatically using libraries (which is probably the best solution if you plan to share your program).

rlwrap solution:

sudo apt-get install rlwrap
rlwrap <command>

EDIT: I was writing a console application in Node.js. To handle user input I'm using basic process.stdin.on("data", ...). The only solution I found is to use built-in readline module. So I wrote a function, which works basically the same as the method I was using before:

const rl = require("readline").createInterface(process.stdin, process.stdout)

function recursiveReadline(prompt, handler) {
    rl.question(prompt, output => {
        if (handler(output.trim()) == 0) return rl.close()
        recursiveReadline(prompt, handler)
    })
}

//
recursiveReadline("> ", (data) => {
    if (data == "exit") return 0 // closes readline
    console.log(data)
})
dwq
  • 11
  • 3
  • Ironically, bar someone who comment-answered in 2014, you've come the closest to the right answer in 9 years. The right answer is to not use C standard library I/O in the first place but to use an input editing library like `libedit` or GNU Readline. The latter is, indeed, what the "rl" in "rlfe" stands for. An alternative is to use non-canonical mode with direct system call I/O and interpret the input control sequences onesself, which involves using, or inventing something akin to, the terminfo/termcap libraries. – JdeBP Jun 06 '23 at 21:01
-8

i think simple way is we can just do kill %% because this sometimes happen because of background processes.

Milan Parmar
  • 110
  • 4