multiline input in terminal

Proposal:

put simply, i need to regularly input multiple lines into my terminal and have python interpret that as is. for an oversimplified example:

Enter your groceries: kiwi
apple
banana
orange

yes, i know there are workarounds such as while loops or sys.stdin.readlines() but those have cons and dont exactly work as intended. for example, sys.stdin.readlines() would require me to only have one needed multiline input.

in my opinion, input() should be for single lines while (something along the lines of) longinput() should take multiple lines into account

Could you explain why you canā€™t use it multiple times? In my testing this wasnā€™t an issue.

2 Likes

because it requires end of file, meaning to close the program. itā€™s a one use thing.

much discussion has been on github already, the issue is linked

Have you tried it?

How is longinput supposed to know when to stop reading lines? One longstanding convention used by POSIX tools like ed is to read until a special line is read. For example, input could be terminated by a line containing . by itself:

>>> x = longinput()
kiwi
apple
banana
orange
.
>>> x
'kiwi\napple\nbanana\norange`

This is relatively trivial to implement yourself if needed; itā€™s not obvious it needs to be a built-in or part of the standard library. (Iā€™d argue that input itself is a fairly trivial wrapper around sys.stdin.readline and would face similar arguments against adding it were it not already in Python.)

5 Likes

Closing standard input does not terminate your program unless youā€™ve written it to exit when it reaches the end of standard input, nor is terminating your program the only way to stop reading from standard input.

It emits a prompt, ensures that output is flushed, then reads a line. This is something that is extremely useful, particularly to new users who might otherwise struggle to get this right; and it just looks ugly and clunky if you get it wrong.

Some languages make their default input function magically flush stdout, and I canā€™t really dispute that, but having a coherent ā€œprompt for inputā€ function is a much less magical way to achieve the same clean result.

3 Likes

when theres no text left to read, ideally python would actually know the amount of lines inputted into the program and stop on the final inputted line. if there is whitespace, theyll be counted as lines

so python would know this is 7 lines (0, 1, 2, 3, 4, 5, 6):

input: apple
banana
grape
whitespace
whitespace
orange
whitespace

in the same way that microsoft word knows how many lines there are in a text and what line youre on, so would python. itā€™d stop upon that. this would also allow you to get the number of lines with len(longinput('input: '))

no, am i wrong here? to my knowledge using ctrl + d turns the program off which is required for that

to my understanding, youre asking if i want to input each line individually and then close out with a ā€˜.ā€™

no, i want to copy and paste a load of lines at the same time. im operating with 400 lines or so at a time. i could end the final line with an ā€˜ENDLINEā€™ so itā€™d be

1
2
3
ā€¦
399
400
ENDLINE

i do not want to input it separately, i want a singular multiline input. i want it to be exactly the same as the regular input but it can understand multiple lines and store them EXACTLY as they were inputted.

if i copy and paste this text into my terminal, i want it stored in python exactly as it is without having to re-input each line over and over. a multiline input.

"Just when he thought to loom the backyard for bud &

Just when he came to admire, or thought to dote over

Already he rues stick-thin arms, whose petals brave the late

Whose middles freeze; weā€™ve gone without

All ramose till now, empty skirts anxious to round back for

Itā€™s the fourth year lips have gone without any such

Already hips full of leaves and none

Else, years by last, the lone ā€” it splat behind

My back, it came to ache as the rake clawed at

Weā€™ve gone into partial burn, without even

No matter for bloom, the seasons no longer allow

The trouble with doting over blossoms is

In a swollen tub of ruth, wanting nothing but his
ENDLINE"

It doesnā€™t. Try it!

1 Like

not a very elegant solution but theres potential. frankly, what ive proposed still seems to make more sense

On Windows, the end of input can be indicated by Ctrl+Z at the start of the line, but Ctrl+D is just accepted as part of the input.

A cross-platform solution would be to use Ctrl+C.

On unix, all ctrl-D does is cause the current read() to return with
whatever is in the input buffer, without waiting for a newline. If there
are no characters in the input buffer, the read() returns 0 bytes. Most
programs take this to mean there is no more input and exit. But thereā€™s
nothing to stop you from going back and doing another read().

However, it seems what is really being asked for is the ability to edit
multiple lines in the terminal window, as though it were a text editor,
and then send them off together. Iā€™m not aware of any existing thing for
doing that. It should be possible, but you would have to put the
terninal in raw mode and implement a mini text editor yourself. Not
exaclty simple to do, and it would probably need different
implementations on different platforms.

if thats not feasible, could longinput() then just go through the lines until it detects ā€˜ENDINPUTā€™ (or perhaps some other phrase which you can put in as an argument into the function, or a number of empty lines) and then aggregate all the lines after theyve all been collected. sorry, thats probably not a well thought out solution but im glad weā€™re now on the same page of what im trying to roughly get at. could you give it a think for some better solution?

How about using tkinter for an editable text box?

2 Likes

while using third party tools is fine, this should be a python feature

How would longinput() know this? Maybe Iā€™m still thinking about the next item to type.

3 Likes

But how is Python supposed to know when youā€™re done inputting lines? Maybe youā€™re just taking a sip of coffee before continuing to type more.

I might just do this:

while block := list(iter(input, 'ENDLINE')):
    print(block)

Input:

1
2
3
ENDLINE
foo
bar
ENDLINE

Output:

['1', '2', '3']
['foo', 'bar']

Attempt This Online!