输入和输出
最后修改于 2023 年 10 月 18 日
在本章中,我们将使用 Tcl 中的输入和输出操作。 Tcl 有几个用于进行 io 的命令。 我们介绍其中的几个。
Tcl 使用称为通道的对象来读写数据。 可以使用 open
或 socket
命令创建通道。 有三个标准通道可供 Tcl 脚本使用,无需显式创建它们。 它们由操作系统为每个新应用程序自动打开。 它们是 stdin
、stdout
和 stderr
。 标准输入 stdin
用于脚本读取数据。 标准输出 stdout
用于脚本写入数据。 标准错误 stderr
用于脚本写入错误消息。
在第一个示例中,我们使用 puts
命令。 它具有以下概要
puts ?-nonewline? ?channelId? string
channelId 是我们要写入文本的通道。 channelId 是可选的。 如果未指定,则假定为默认值 stdout
。
#!/usr/bin/tclsh puts "Message 1" puts stdout "Message 2" puts stderr "Message 3"
puts
命令将文本写入通道。
puts "Message 1"
如果未指定 channelId,则默认情况下我们会写入 stdout
。
puts stdout "Message 2"
此行与前一行执行相同的操作。 我们仅显式指定了 channelId。
puts stderr "Message 3"
我们写入标准错误通道。 默认情况下,错误消息将转到终端。
$ ./printing.tcl Message 1 Message 2 Message 3
示例输出。
read 命令
read
命令用于从通道读取数据。 可选参数指定要读取的字符数。 如果省略,该命令将从通道读取所有数据,直到结尾。
#!/usr/bin/tclsh set c [read stdin 1] while {$c != "q"} { puts -nonewline "$c" set c [read stdin 1] }
该脚本从标准输入通道读取一个字符,然后将其写入标准输出,直到遇到字符 q。
set c [read stdin 1]
我们从标准输入通道 (stdin) 读取一个字符。
while {$c != "q"} {
我们继续读取字符,直到按下 q。
gets 命令
gets
命令从通道读取下一行,返回该行中除换行符以外的所有内容。
#!/usr/bin/tclsh puts -nonewline "Enter your name: " flush stdout set name [gets stdin] puts "Hello $name"
该脚本请求用户输入,然后打印一条消息。
puts -nonewline "Enter your name: "
puts
命令用于将消息打印到终端。 -nonewline
选项禁止换行符。
flush stdout
Tcl 在内部缓冲输出,因此使用 puts
写入的字符可能不会立即出现在输出文件或设备上。 flush
命令强制立即显示输出。
set name [gets stdin]
gets
命令从通道读取一行。
$ ./hello.tcl Enter your name: Jan Hello Jan
该脚本的示例输出。
pwd 和 cd 命令
Tcl 具有 pwd
和 cd
命令,类似于 shell 命令。 pwd
命令返回当前工作目录,而 cd
命令用于更改工作目录。
#!/usr/bin/tclsh set dir [pwd] puts $dir cd .. set dir [pwd] puts $dir
在此脚本中,我们打印当前工作目录。 然后我们更改工作目录并再次打印工作目录。
set dir [pwd]
pwd
命令返回当前工作目录。
cd ..
我们将工作目录更改为当前目录的父目录。 我们使用 cd
命令。
$ ./cwd.tcl /home/janbodnar/prog/tcl/io /home/janbodnar/prog/tcl
示例输出。
glob 命令
Tcl 具有一个 glob
命令,该命令返回与模式匹配的文件名。
#!/usr/bin/tclsh set files [glob *.tcl] foreach file $files { puts $file }
该脚本将所有扩展名为 .tcl
的文件打印到控制台。
set files [glob *.tcl]
glob
命令返回与 *.tcl
模式匹配的文件列表。
foreach file $files { puts $file }
我们遍历文件列表,并将列表中的每个项目打印到控制台。
$ ./globcmd.tcl attributes.tcl allfiles.tcl printing.tcl hello.tcl read.tcl files.tcl globcmd.tcl write2file.tcl cwd.tcl readfile.tcl isfile.tcl addnumbers.tcl
这是 globcmd.tcl
脚本的示例输出。
使用文件
file
命令操作文件名和属性。 它有很多选项。
#!/usr/bin/tclsh puts [file volumes] [file mkdir new]
该脚本打印系统已安装的卷并创建一个新目录。
puts [file volumes]
file volumes
命令返回系统上已安装的卷的绝对路径。
[file mkdir new]
file mkdir
创建一个名为 new
的目录。
$ ./voldir.tcl / $ ls -d */ doc/ new/ tmp/
在 Linux 系统上,有一个已安装的卷 - 根目录。 ls
命令确认创建了 new
目录。
在以下代码示例中,我们将检查文件名是常规文件还是目录。
#!/usr/bin/tclsh set files [glob *] foreach fl $files { if {[file isfile $fl]} { puts "$fl is a file" } elseif { [file isdirectory $fl]} { puts "$fl is a directory" } }
我们遍历当前工作目录中的所有文件名,并打印它是文件还是目录。
set files [glob *]
使用 glob
命令,我们创建一个当前目录的文件和目录名称列表。
if {[file isfile $fl]} {
如果相关文件名是一个文件,我们执行 if
命令的主体。
} elseif { [file isdirectory $fl]} {
file isdirectory
命令确定文件名是目录还是目录。 请注意,在 Unix 上,目录是文件的一种特殊情况。
puts
命令可用于写入文件。
#!/usr/bin/tclsh set fp [open days w] set days {Monday Tuesday Wednesday Thursday Friday Saturday Sunday} puts $fp $days close $fp
在脚本中,我们打开一个文件进行写入。 我们将一周的日期写入一个文件。
set fp [open days w]
我们打开一个名为 days
的文件进行写入。 open
命令返回一个通道 ID。
set days {Monday Tuesday Wednesday Thursday Friday Saturday Sunday}
此数据将要写入该文件。
puts $fp $days
我们使用 open
命令返回的通道 ID 写入文件。
close $fp
我们关闭打开的通道。
$ ./write2file.tcl $ cat days Monday Tuesday Wednesday Thursday Friday Saturday Sunday
我们运行该脚本并检查 days 文件的内容。
在以下脚本中,我们将从文件读取数据。
$ cat languages Python Tcl Visual Basic Perl Java C C# Ruby Scheme
我们有一个名为 languages 的简单文件,位于一个目录中。
#!/usr/bin/tclsh set fp [open languages r] set data [read $fp] puts -nonewline $data close $fp
我们从提供的文件读取数据,读取其内容并将数据打印到终端。
set fp [open languages r]
我们通过以只读模式打开 languages 文件来创建一个通道。
set data [read $fp]
如果未向 read
命令提供第二个参数,则它将从文件读取所有数据,直到文件结尾。
puts -nonewline $data
我们将数据打印到控制台。
$ ./readfile.tcl Python Tcl Visual Basic Perl Java C C# Ruby Scheme
readfile.tcl
脚本的示例运行。
eof
命令检查所提供的通道的行尾。
#!/usr/bin/tclsh set fp [open languages] while {![eof $fp]} { puts [gets $fp] } close $fp
我们使用 eof
命令读取文件的内容。
while {![eof $fp]} { puts [gets $fp] }
该循环将继续,直到 eof
在遇到文件结尾时返回 true。 在主体内,我们使用 gets
命令从文件读取一行。
$ ./readfile2.tcl Python Tcl Visual Basic Perl Java C C# Ruby Scheme
readfile2.tcl
脚本的示例运行。
下一个脚本执行一些附加的文件操作。
#!/usr/bin/tclsh set fp [open newfile w] puts $fp "this is new file" flush $fp file copy newfile newfile2 file delete newfile close $fp
我们打开一个文件并将一些文本写入其中。 复制该文件。 然后删除原始文件。
file copy newfile newfile2
file copy
命令复制一个文件。
file delete newfile
使用 file delete
命令删除原始文件。
在最后一个示例中,我们使用文件属性。
#!/usr/bin/tclsh set files [glob *] set mx 0 foreach fl $files { set len [string length $fl] if { $len > $mx} { set mx $len } } set fstr "%-$mx\s %-s" puts [format $fstr Name Size] set fstr "%-$mx\s %d bytes" foreach fl $files { set size [file size $fl] puts [format $fstr $fl $size] }
该脚本创建两列。 在第一列中,我们包含文件名。 在第二列中,我们显示文件的大小。
foreach fl $files { set len [string length $fl] if { $len > $mx} { set mx $len } }
在此循环中,我们找出最长的文件名。 这将用于格式化输出列。
set fstr "%-$mx\s %-s" puts [format $fstr Name Size]
在这里,我们打印列的标题。 为了格式化数据,我们使用 format
命令。
set fstr "%-$mx\s %d bytes" foreach fl $files { set size [file size $fl] puts [format $fstr $fl $size] }
我们遍历文件列表并打印每个文件名及其大小。 file size
命令确定文件的大小。
$ ./attributes.tcl Name Size attributes.tcl 337 bytes newfile2 17 bytes allfiles.tcl 75 bytes printing.tcl 83 bytes languages 51 bytes hello.tcl 109 bytes days 57 bytes read.tcl 113 bytes files.tcl 140 bytes globcmd.tcl 82 bytes write2file.tcl 134 bytes doc 4096 bytes cwd.tcl 76 bytes tmp 4096 bytes readfile.tcl 98 bytes isfile.tcl 219 bytes
示例运行。
在本章中,我们介绍了 Tcl 中的输入/输出操作。