Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

The function of the command `stty raw'.

95 views
Skip to first unread message

hongy...@gmail.com

unread,
Jan 13, 2021, 7:53:29 PM1/13/21
to
The following tcl and shell mixing script is one of the examples taken from the directory of the expect5.45.4 distribution:

#------> begin of the excerption <-------
$ cat expect5.45.4/example/read1char
#!/bin/sh
# -*- tcl -*-
# The next line is executed by /bin/sh, but not tcl \
exec tclsh "$0" ${1+"$@"}

package require Expect

# read a single character
# Author: Don Libes, NIST

stty raw
expect ?
send_user $expect_out(buffer)
#------> end of the excerption <-------

I really can't figure out what's the function of the following two lines used as shown above:

stty raw
expect ?

Any hints will be highly appreciated.

Regards,
HY

John-Paul Stewart

unread,
Jan 14, 2021, 11:34:50 AM1/14/21
to
As I mentioned in my other recent post, after 'exec tclsh', the original
shell is gone and you are running tclsh code. So those are tclsh
commands which may behave differently than any similarly named shell
commands. Look them up in the documentation for Tcl or tclsh to find
out what they are for.

Lew Pitcher

unread,
Jan 14, 2021, 12:37:05 PM1/14/21
to
The hashbang line starts /bin/bash, which interprets the script
One of the first instructions in the script
exec tclsh "$0" ${1+"$@"}
replaces /bin/bash with the tclsh TCL shell interpreter, which interprets
the remainder of the script. So, the remaining lines
package require Expect
# read a single character
# Author: Don Libes, NIST

stty raw
expect ?
send_user $expect_out(buffer)
are all written in the TCL shell language

The first line
package require Expect
tells tclsh to use a specific package of subroutines: the "Expect"
package.

Expect is
"a program that "talks" to other interactive programs according to a
script. Following the script, Expect knows what can be expected from
a program and what the correct response should be. An interpreted
language provides branching and high-level control structures to
direct the dialogue. In addition, the user can take control and
interact directly when desired, afterward returning control to the
script." (expect(1) INTRODUCTION)
More specifically, expect allows you to build programs that converse
interactivly with other programs, reading from their stdout for responses
and writing to their stdin to supply instructions.

An expect(1) script accepts both expect(1) commands /and/ "command-
line" (for want of a better term) commands. What is /not/ an expect(1)
command is assumed to be a "command-line" command. So...
stty raw
not being an expect(1) command, is taken as the commandline command
stty raw
which sets the terminal into "raw" mode, removing the special
interpretation usually given to various control-characters that you might
receive or enter into a terminal (see stty(1))

Next,
expect ?
being an expect(1) command, is interpreted by expect(1). Specifically, it
tells expect(1) to read and accept any sort of response from the terminal

Finally,
send_user $expect_out(buffer)
being another expect(1) command, is interpreted by expect(1) to display
on the user's terminal the data in $expect_out(buffer)


HTH
--
Lew Pitcher
"In Skills, We Trust"

Javier

unread,
Jan 14, 2021, 6:31:24 PM1/14/21
to
Actually tclsh would interpret the whole script, including the line

exec tclsh "$0" ${1+"$@"}

I don't know what tcl would do with that line, since I don't know tcl.
Possibly it would just ignore it, but I'm not sure.

The shebang line '#!/bin/sh' and the other comments tcl would treat as comments,
since that is the convention for most scripting languages (python, perl, etc).
But that would not be case for the Lua language, where comments start with --
instead of #.

Lew Pitcher

unread,
Jan 14, 2021, 7:08:53 PM1/14/21
to
Good point. I missed that consideration.

> I don't know what tcl would do with that line, since I don't know tcl.
> Possibly it would just ignore it, but I'm not sure.

Neither am I. That's something to look into, I guess

hongy...@gmail.com

unread,
Jan 14, 2021, 8:46:36 PM1/14/21
to
Why not use a more rigorous checklist that works in both cases of $1, i.e., null or unset, as shown below:

${1:+"$@"}'

See <https://unix.stackexchange.com/questions/68484/what-does-1-mean-in-a-shell-script-and-how-does-it-differ-from> for the more detailed discussion.
I can't find the above description from the document:

$ man stty | egrep -A3 -i '^[ ]+raw'
raw same as -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr
-igncr -icrnl -ixon -ixoff -icanon -opost -isig -iuclc -ixany
-imaxbel -xcase min 1 time 0

Lew Pitcher

unread,
Jan 14, 2021, 11:23:21 PM1/14/21
to
On Thu, 14 Jan 2021 17:46:32 -0800, hongy...@gmail.com wrote:

> On Friday, January 15, 2021 at 1:37:05 AM UTC+8, Lew Pitcher wrote:
>> On Wed, 13 Jan 2021 16:53:26 -0800, hongy...@gmail.com wrote:
>>
>> > The following tcl and shell mixing script is one of the examples
>> > taken
>> from the directory of the expect5.45.4 distribution:
>> >
>> > #------> begin of the excerption <-------
>> > $ cat expect5.45.4/example/read1char #!/bin/sh # -*- tcl -*-
>> > # The next line is executed by /bin/sh, but not tcl \
>> > exec tclsh "$0" ${1+"$@"}
>> >
>> > package require Expect
>> >
>> > # read a single character # Author: Don Libes, NIST
>> >
>> > stty raw expect ?
>> > send_user $expect_out(buffer)
>> > #------> end of the excerption <-------
>> >
>> > I really can't figure out what's the function of the following two
>> lines used as shown above:
>> >
>> > stty raw expect ?
>> >
>> > Any hints will be highly appreciated.
>> The hashbang line starts /bin/bash, which interprets the script One of
>> the first instructions in the script exec tclsh "$0" ${1+"$@"}
>
> Why not use a more rigorous checklist that works in both cases of $1,
> i.e., null or unset, as shown below:

Don't ask me, I didn't write that script. It's certainly not how I would
implement an expect script.


> ${1:+"$@"}'
>
> See
> <https://unix.stackexchange.com/

I'd rather not. I rarely take the advice of a multitude of amateurs and
self-taught programmers answering questions from other amateurs.
[snip]
>> stty raw not being an expect(1) command, is taken as the commandline
>> command stty raw which sets the terminal into "raw" mode, removing the
>> special interpretation usually given to various control-characters that
>> you might receive or enter into a terminal (see stty(1))
>
> I can't find the above description from the document:
>
> $ man stty | egrep -A3 -i '^[ ]+raw'
> raw same as -ignbrk -brkint -ignpar -parmrk -inpck -istrip
> -inlcr
> -igncr -icrnl -ixon -ixoff -icanon -opost -isig -iuclc
> -ixany -imaxbel -xcase min 1 time 0

Then you either didn't read the stty(1) manpage well enough, or you don't
understand what you are reading.

Quote:
raw same as -ignbrk -brkint -ignpar -parmrk -inpck -istrip
-inlcr -igncr -icrnl -ixon -ixoff -icanon -opost
-isig -iuclc -ixany -imaxbel -xcase min 1 time 0
endquote

For stty, "- before SETTING indicates negation",

-ignbrk /DONT/ ignore break characters (break is a logic-low
signal sent over a serial line /instead/ of the usual
mark/space of a valid character, usually indicating some
sort of data interruption

-brkint breaks /DO NOT/ cause an interrupt signal

-ignpar /DONT/ ignore characters with parity errors

-parmrk /DONT/ mark parity errors

-inpck /DONT/ enable parity checking

-istrip /DONT/ clear high bit of input characters

-inlcr /DONT/ translate newline to carriage return

-igncr /DONT/ ignore carriage return

-icrnl /DONT/ translate carriage return to newline

-ixon /DONT/ enable XON/XOFF flow control

-ixoff /DONT/ enable sending of start/stop characters

-icanon /DONT/ enable special characters; erase/kill/werase/rprnt

-opost /DONT/ postprocess output

-isig /DONT/ enable interrupt, quit, and suspend special
characters

-iuclc /DONT/ translate uppercase characters to lowercase

-ixany /DONT/ let any character restart output

-imaxbel /DONT/ beep, and do flush a full input buffer

-xcase /DONT/ escape with '\' for uppercase characters

Note that the default terminal settings are represented by the stty
"sane" value (see stty(1) for what that means), which, for the most part,
is exactly the opposite of the "raw" settings.

[snip]

Janis Papanagnou

unread,
Jan 15, 2021, 2:03:28 AM1/15/21
to
On 15.01.2021 02:46, hongy...@gmail.com wrote:
> On Friday, January 15, 2021 at 1:37:05 AM UTC+8, Lew Pitcher wrote:
>> On Wed, 13 Jan 2021 16:53:26 -0800, hongy...@gmail.com wrote:
>>> #!/bin/sh
>>> exec tclsh "$0" ${1+"$@"}
>>>
>> The hashbang line starts /bin/bash, which interprets the script
>> One of the first instructions in the script
>> exec tclsh "$0" ${1+"$@"}
>
> Why not use a more rigorous checklist that works in both cases of $1, i.e., null or unset, as shown below:
>
> ${1:+"$@"}

I seem to recall that the idiom ${1+"$@"} was historically used to
work around a bug (or misconception) in the Bourne shell. (Use Google
to find details about the historic shell behavior.)

The reason why the colon substitution variant :+ is not used is that
the _intended behavior_ is then not achieved. If your first argument
expands to an empty argument, then all your arguments for the tclsh
call would be discarded; compare behavior of providing the arguments
a b c and "" b c respectively. With the colon tclsh won't
see any of the three arguments, with the colon it gets all the three
including the empty one.

Janis

Janis Papanagnou

unread,
Jan 15, 2021, 2:15:40 AM1/15/21
to
On 15.01.2021 05:23, Lew Pitcher wrote:
> On Thu, 14 Jan 2021 17:46:32 -0800, hongy...@gmail.com wrote:
>> On Friday, January 15, 2021 at 1:37:05 AM UTC+8, Lew Pitcher wrote:
>>> The hashbang line starts /bin/bash, which interprets the script One of
>>> the first instructions in the script exec tclsh "$0" ${1+"$@"}
>>
>> Why not use a more rigorous checklist that works in both cases of $1,
>> i.e., null or unset, as shown below:
>
> Don't ask me, I didn't write that script. It's certainly not how I would
> implement an expect script.
>
>> ${1:+"$@"}'
>>
>> See
>> <https://unix.stackexchange.com/
>
> I'd rather not. I rarely take the advice of a multitude of amateurs and
> self-taught programmers answering questions from other amateurs.

Actually, in this case, the accepted answer in above link came from
Stefane Chazelas (who formerly posted here in CUS) who is certainly
not an amateur. That answer also explains the historic rationale for
that idiom:
"$@" expands to one empty argument if the list of positional
parameters is empty ($# == 0) instead of no argument at all.
On the other hand, you can also read there in the edit of the poster:
"Two answers below say that it's supposed to be ${1:+"$@"}."
which backups your point about many amateurs lurking around there.

Janis

hongy...@gmail.com

unread,
Jan 15, 2021, 2:42:56 AM1/15/21
to
On Friday, January 15, 2021 at 3:03:28 PM UTC+8, Janis Papanagnou wrote:
> On 15.01.2021 02:46, hongy...@gmail.com wrote:
> > On Friday, January 15, 2021 at 1:37:05 AM UTC+8, Lew Pitcher wrote:
> >> On Wed, 13 Jan 2021 16:53:26 -0800, hongy...@gmail.com wrote:
> >>> #!/bin/sh
> >>> exec tclsh "$0" ${1+"$@"}
> >>>
> >> The hashbang line starts /bin/bash, which interprets the script
> >> One of the first instructions in the script
> >> exec tclsh "$0" ${1+"$@"}
> >
> > Why not use a more rigorous checklist that works in both cases of $1, i.e., null or unset, as shown below:
> >
> > ${1:+"$@"}
> I seem to recall that the idiom ${1+"$@"} was historically used to
> work around a bug (or misconception) in the Bourne shell. (Use Google
> to find details about the historic shell behavior.)
>
> The reason why the colon substitution variant :+ is not used is that
> the _intended behavior_ is then not achieved.

Thanks for pointing this out. This is a legitimate reason, IMHO.

> If your first argument expands to an empty argument, then all your arguments for the tclsh
> call would be discarded; compare behavior of providing the arguments
> a b c and "" b c respectively. With the colon tclsh won't see any of the three arguments,
> with the colon it gets all the three including the empty one.

I guess it must be your typo here. You should have intended to enter 'without'.

HY

Janis Papanagnou

unread,
Jan 15, 2021, 4:27:43 AM1/15/21
to
I repeat: "With the colon tclsh won't see any of the three arguments"

You can always verify behavior (or given statements) by a test script,
for example using:

echo without colon
printf '"%s"\n' tclsh "$0" ${1+"$@"}
echo with colon
printf '"%s"\n' tclsh "$0" ${1:+"$@"}

and call it with arguments a b c and "" b c respectively.

Janis

> HY
>

Janis Papanagnou

unread,
Jan 15, 2021, 4:35:58 AM1/15/21
to
On 15.01.2021 10:27, Janis Papanagnou wrote:
>
> I repeat: "With the colon tclsh won't see any of the three arguments"
>
> You can always verify behavior (or given statements) by a test script,

Or you can *read* the sources that you provided yourself upthread,
where Stefane explained it and also gave a comment to someone elses
wrong statement:

No, ${1:+"$@"} would expand to no argument if $1 was empty. You
want ${1+"$@"}. Basically you have it reversed. – Stéphane Chazelas


Hongyi, please do us a favor and invest a bit more time and effort
to understand the information that is already provided (by yourself
and others).

Janis

hongy...@gmail.com

unread,
Jan 15, 2021, 8:56:03 AM1/15/21
to
Thank you for your pertinent advice.

HY

hongy...@gmail.com

unread,
Jan 15, 2021, 9:01:08 AM1/15/21
to
I really have read and thought on this problem for a long time, but never try to think of the intuitive and concise test method given above. It's my shame and thanks again for guiding me to the correct leaning direction.

Best,
HY

Jim Jackson

unread,
Jan 15, 2021, 12:19:51 PM1/15/21
to
>>> The following tcl and shell mixing script is one of the examples taken
>> from the directory of the expect5.45.4 distribution:
>>>
>>> #------> begin of the excerption <-------
>>> $ cat expect5.45.4/example/read1char
>>> #!/bin/sh
>>> # -*- tcl -*-
>>> # The next line is executed by /bin/sh, but not tcl \

Will people please note the trailing '\' on the above line.

>>> exec tclsh "$0" ${1+"$@"}
>>>
>>> package require Expect
>>>
>>> # read a single character
>>> # Author: Don Libes, NIST
>>>
>>> stty raw
>>> expect ?
>>> send_user $expect_out(buffer)
>>> #------> end of the excerption <-------
>>>
>>> I really can't figure out what's the function of the following two
>> lines used as shown above:
>>>
>>> stty raw
>>> expect ?
>>>
>>> Any hints will be highly appreciated.
>>
>> The hashbang line starts /bin/bash, which interprets the script
>> One of the first instructions in the script
>> exec tclsh "$0" ${1+"$@"}
>> replaces /bin/bash with the tclsh TCL shell interpreter, which interprets
>> the remainder of the script. So, the remaining lines
>
> Actually tclsh would interpret the whole script, including the line
>
> exec tclsh "$0" ${1+"$@"}

Except tclsh "sees" the trailing '\' in the previous comment line and hence
thinks that this is a continuation of the comment, and hence would be ignored.

It would than continue interpreting the rest of the tcl script.

Javier

unread,
Jan 15, 2021, 12:59:46 PM1/15/21
to
Jim Jackson <j...@franjam.org.uk> wrote:
>>>> #------> begin of the excerption <-------
>>>> $ cat expect5.45.4/example/read1char
>>>> #!/bin/sh
>>>> # -*- tcl -*-
>>>> # The next line is executed by /bin/sh, but not tcl \
>
> Will people please note the trailing '\' on the above line.
>
>>>> exec tclsh "$0" ${1+"$@"}
>>>>
>>>> package require Expect
>>>>
>>>> # read a single character
>>>> # Author: Don Libes, NIST

When I wrote the message I didn't realize who was the original author of
the script.

https://openlibrary.org/books/OL1714744M/Obfuscated_C_and_other_mysteries

A very clever man indeed.

Brian Patrie

unread,
Jan 16, 2021, 6:29:32 AM1/16/21
to
On 14/01/2021 22.23, Lew Pitcher wrote:
> Note that the default terminal settings are represented by the
> stty "sane" value (see stty(1) for what that means), which, for
> the most part, is exactly the opposite of the "raw" settings.

And the actual opposite of "raw" is "cooked".
0 new messages