キーボードやファイルから文字列を行単位で入力するには、getsコマンドを使います。逆に、文字列を行単位で画面やファイルに出力するにはputsコマンドを使います。
Tclで扱うデータは、基本的に全て文字列として扱われますが、演算処理を行う際に数字は数値として扱われます。また、binaryコマンドを使ってバイナリデータを扱うこともできます。
この記事では、標準入出力の説明と、キーボードから文字列を入力する方法と画面へ出力する方法を説明します。
ファイルの入出力につては別の記事で紹介します。
binaryコマンドにつての説明は別の記事で紹介します。
標準入出力について
[標準入出力チャネルのイメージ]
プログラムが起動されると、OSはプロセスという単位でプログラムを管理します。各プロセスには標準で標準入力チャネル、標準出力チャネル、標準エラーチャネルの3つの入出力チャネルが割当てられます。
チャネルとは、データを受け渡しするための通路のことです。プログラムは、このチャネルを通してI/O(デバイスやファイル)とデータの入出力を行います。
特に指定のない状態では、標準入力はキーボード、標準出力と標準エラーはディスプレイとつながっています。
文字列を画面に表示する
画面に文字列を表示するには、putsコマンドを使います。
[書式]
puts ?-nonewline? ?channelID? string
putsコマンドは、string(文字列)の末尾に「改行」を追加して、指定したchannelIDへ出力します。channelIDを省略すると、stdout(標準出力)に出力します。 -nonewline を指定すると改行しません。
サンプルプログラム : hello.tcl
#!/bin/sh # the next line restarts using tclsh \ exec tclsh "$0" "$@" puts stdout "hello, world!"
[実行例]
$ ./hello.tcl hello, world!
バッファリングについて
入出力チャネルには、データを一時的に保持しておく記憶域があります。この記憶域のことを、バッファといいます。
バッファは日本語で「緩衝」という意味になります。プログラムとデバイス間の入出力処理において、「データの入出力(受け渡し)」と「プログラムやデバイスの処理」との間で生じる時間のズレを調整・吸収する為に用意されています。
チャネルによるデータの入出力は、基本的にバッファを介して行われます。
バッファからデバイスへのデータ転送は、バッファが一杯になるか、チャネルがクローズされるまで遅延されます。このようにバッファを介した動作をバッファリングといいます。
明示的にフラッシュ(吐き出し)するには、Tclではflushコマンドを使います。Tclのputsコマンドは、画面に文字列を出力すると、改行ごとに自動でフラッシュされます。
キーボードから文字を入力する
キーボードから文字を入力するにはgetsコマンドを使います。
[書式]
gets channelId ?varName?
getsコマンドは、指定した channelID から1行読み込みます。行の終端文字(null:0)は破棄されます。
varName が省略された場合、入力された文字列を返します。 varName が指定された場合、入力された文字列は varName 変数に格納され、戻り値は入力された文字数を返します。
サンプルプログラム : input.tcl
#!/bin/sh # the next line restarts using tclsh \ exec tclsh "$0" "$@"
puts "何か数字を入力してください。:"
set var [gets stdin] puts "入力した数字は $var ですね。"
[実行例1.1]
$ ./input.tcl 何か数字を入力してください。: 12 入力した数字は 12 ですね。
上記の例では、「何か数字を入力してください。:」を表示した後に改行されています。
改行せずに、メッセージの横に入力できるようにするには、以下のように -nonewline を指定します。
puts -nonewline "何か数字を入力してください。:"
これを実行すると、以下のようになり、「何か数字を入力してください。:」のメッセージが表示しません。しかし、そのまま何か数字を入力して改行(エンター)すると表示されます。
[実行例1.2]
$ ./input.tcl 12 何か数字を入力してください。:入力した数字は 12 ですね。
ちょっと表示が変ですね。
これはバッファリングが行われた影響によるものです。putsコマンドでバッファに溜まったデータをすぐに出力するには、flushコマンドを使います。
サンプルプログラム : input2.tcl
#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"
puts -nonewline "何か数字を入力してください。:"
flush stdout
set var [gets stdin]
puts "入力した数字は $var ですね。"
[実行例2]
$ ./input.tcl 何か数字を入力してください。:12 入力した数字は 12 ですね。
flush stdout は標準出力チャネルのバッファに溜まったデータを吐き出します。これで、意図した通りの出力になりました。
次のサンプルコードはgetsコマンドの引数に varName を指定した場合の例です。
サンプルプログラム : input3.tcl
#!/bin/sh # the next line restarts using tclsh \ exec tclsh "$0" "$@" puts -nonewline "好きな果物は何ですか?:" flush stdout
set num [gets stdin str] puts "好きな果物は $str ですね。文字数は $num です。"
[実行例3]
$ ./input3.tcl 好きな果物は何ですか?:バナナ 好きな果物は バナナ ですね。文字数は 3 です。
getsコマンドの引数に varName を指定すると、入力された文字列は varName変数に格納され、戻り値は入力された文字数を返します。(例では varName変数:strです)
これは入力の有無や、入力された文字数を確認する必要がある場合に利用できます。
コメント
いつもわかりやすい記事をありがとうございます。
私の tclshのUIが白黒のみで見づらく、主のような見やすいUIにしたいのですが、どこで設定できますか?
また、上キーを押すと% ^[[A と出てきて履歴を遡れません。この辺の設定の仕方も教えていただけると幸いです。
コメントありがとうございます。
記事のサンプルコードがカラー表示しているのは、Webページ作成時に以下の機能を使っています。
https://wp-cocoon.com/highlight-js/
tclsh自体にはソースコードに色を付ける機能はないです。
私のターミナル(端末)画面もモノクロです。
なおにぃさんの使用環境がわかりませんが、テキストエディターに文字列を強調する機能があれば、テキストエディタ上での表示は変える事ができます。私もテキストエディターで強調機能を使っています。
>上キーを押すと% ^[[A と出てきて履歴を遡れません。
残念ならがtclshにはBashのようなヒストリ機能はありません。ですが、もしLinux(Unix)をご使用という事であれば、rlwrapコマンドと組み合わせる事でヒストリ機能が使える可能性があります。
※なおにぃさんの使用環境でrlwrapコマンドが使えるのならという事ですが。
CentOSとFreeBSDでのやり方の記事を新規投稿したので参考にしてください。
https://blog.it-see.net/it-dokata/tcl-tk/tclsh-command-history/
丁寧なご回答ありがとうございます。
tclshにはハイライト機能がないのですね。
rlwrapに関しても調べてみます。
ありがとうございました!