In TCL, how to append different content into a single file using the for loop or foreach loop?
Did you mean something like that?
set fo [open file a]
foreach different_content {"text 1" "text two" "something else" "some content"} {
puts $fo $different_content
}
close $fo
You open file file in mode a (append) and write to the file descriptor ($fo in the example).
Update: If you want to append variable contents, you have to change the script to:
set fo [open file a]
foreach different_content [list $data1 $data2 $data3 $data4] {
puts $fo $different_content
}
close $fo
The following code creates a text file in folder 'P' and writes into it.
set fid [open p:\\temp.txt w]
puts $fid "here is the first line."
close $fid
The following code is fine for reading from a file, where sample.tcl file is available in 'p' folder.
Heading
set fp [open "p://sample.tcl" r]
set file_data [read $fp]
puts $file_data
close $fp
Related
can anyone tell me how I can update the following procedure to handle big files please (size <= 10 G):
proc read_text_file { file } {
set fp [open ${file} r]
set return_data ""
while { [gets $fp each_line] != -1 } {
lappend return_data ${each_line}
}
close $fp
return ${return_data}
}
my objective is to read a huge file line by line in a better runtime
Thanks
When you have a very large file, you categorically want to avoid bringing it all into memory at once. (Also, Tcl 8.* has a memory chunk allocation limit that makes bringing in 50GB of data intensely exciting. That's a long-standing API bug that's fixed in 9.0 — in alpha — but you'll have to put up with it for now.)
If you can, do a pass over the file to identify where the interesting sub-chunks of it are. For the sake of argument, let's assume that those are the lines that match a pattern; here's an example that finds where procedures are in a Tcl script (under some simple assumptions).
proc buildIndices {filename} {
set f [open $filename]
set indices {}
try {
while {![eof $f]} {
set idx [tell $f]
set line [gets $f]
if {[regexp {^proc (\w+)} $line -> name]} {
dict set indices $name $idx
}
}
return $indices
} finally {
close $f
}
}
Now you have the indices, you can then pull in a procedure from the file like this:
proc obtainProcedure {filename procName indices} {
set f [open $filename]
try {
seek $f [dict get $indices $procName]
set procedureDefinition ""
while {[gets $f line] >= 0} {
append procedureDefinition $line "\n"
if {[info complete $procedureDefinition]} {
# We're done; evaluate the script in the caller's context
tailcall eval $procedureDefinition
}
}
} finally {
close $f
}
}
You'd use that like this:
# Once (possibly even save this to its own file)
set indices [buildIndices somefile.tcl]
# Then, to use
obtainProcedure somefile.tcl foobar $indices
If you're doing this a lot, convert your code to use a database; they're a lot more efficient in the long run. The index building is equivalent to building the database and the other procedure is equivalent to doing a DB query.
I'm trying to read a huge gz file line by line in Perl6.
I'm trying to do something like this
my $file = 'huge_file.gz';
for $file.IO.lines -> $line {
say $line;
}
But this give error that I have a malformed UTF-8. I can't see how to get this to read gzipped material from the help page https://docs.perl6.org/language/unicode#UTF8-C8 or https://docs.perl6.org/language/io
I want to accomplish the same thing as was done in Perl5: http://blog-en.openalfa.com/how-to-read-and-write-compressed-files-in-perl
How can I read a gz file line by line in Perl6?
thanks
I would recommend using the module Compress::Zlib for this purpose. You can find the readme and code on github and install it with zef install Compress::Zlib.
This example is taken from the test file number 3 titled "wrap":
use Test;
use Compress::Zlib;
gzspurt("t/compressed.gz", "this\nis\na\ntest");
my $wrap = zwrap(open("t/compressed.gz"), :gzip);
is $wrap.get, "this\n", 'first line roundtrips';
is $wrap.get, "is\n", 'second line roundtrips';
is $wrap.get, "a\n", 'third line roundtrips';
is $wrap.get, "test", 'fourth line roundtrips';
This is probably the easiest way to get what you want.
use the read-file-content method in the Archive::Libarchive module, but i don't know if the method read all lines into memory at once:
use Archive::Libarchive;
use Archive::Libarchive::Constants;
my $a = Archive::Libarchive.new: operation => LibarchiveRead, file => 'test.tar.gz';
my Archive::Libarchive::Entry $e .= new;
my $log = '';
while $a.next-header($e) {
$log = get-log($a,$e) if $e.pathname.ends-with('.txt');
}
sub get-log($a, $e) {
return $a.read-file-content($e).decode('UTF8-C8');
}
If you are after a quick solution you can read the lines from the stdout pipe of a gzip process:
my $proc = run :out, "gzip", "--to-stdout", "--decompress", "MyFile.gz"
for $proc.out.lines -> $line {
say $line;
}
$proc.out.close;
I have a list of IPs that I am looping through to ssh into each of them and capture some logs. Currently, it will loop through all the IPs and do what I want, the issue occurs when it hits the last IP, after it is done with the last line, it attempts to spawn another empty line resulting in an error. (spawn ssh root#)
How can I prevent this error from happening?
myexpect.sh
set user user
set pass pass
set timeout 600
# Get the list of hosts, one per line #####
set f [open "/my/ip/list.txt"]
set hosts [split [read $f] "\n"]
close $f
# Iterate over the hosts
foreach host $hosts {
spawn ssh $user#$host
expect {
"connecting (yes/no)? " {send "yes\r"; exp_continue}
"assword: " {send "$pass\r"}
}
expect "# "
send "myscript.sh -x\r"
expect "# "
send "exit\r"
expect eof
}
myiplist.txt
172.17.255.255
172.17.255.254
...
error:
[root#172.17.255.255: ]# exit //last ip in the list
Connection to 172.17.255.255 closed.
spawn ssh root#
ssh: Could not resolve hostname : Name or service not known
expect: spawn id exp5 not open
Text files end with a newline
first line\n
...
last line\n
So when you read the whole file into a variable, then split on newlines, your list looks like this:
{first line} {...} {last line} {}
because there is an empty string after the last newline.
The idiomatic way to iterate over the lines of a file in Tcl/expect is this:
set f [open file r]
while {[gets $f host] != -1} {
do something with $host
}
close $f
Or, use the -nonewline option of the read command
set f [open file]
set hosts [split [read -nonewline $f] \n]
close $f
foreach host $hosts {...}
I wanted to open a text file and read the first 10 line by using CGI and Perl
I wrote the script but it does not work. where is my problem
#!C:/wamp/apps/Perl/bin/perl.exe -wt
use CGI;
my $cgi=CGI->new();
print
$cgi->header('text/html'),
$cgi->start_html('Extract the text'),
$cgi->h1({-style=>'color:red;background-color:#eee;'},'Extract CGI'),
$cgi->start_form(-enctype=>&CGI::MULTIPART),
'Upload your text File: ',
$cgi->filefield(
-name=>'filename',
),
$cgi->submit(-value=>'Read the File'),
my $txtfile=$cgi->param('filename'),
open my $in,$filename or die("couldnot open");
while (my $line = <$in>)
{
print $line;
last if $. == 10;
}
close $in;
$cgi->end_form;
$cgi->end_html;
you might find this useful
http://www.sitepoint.com/uploading-files-cgi-perl-2/
basically, the file uploaded is not named the same as the file passed in from the browser
You need to do some checks on what you've been sent first
I just want to iterate through a list of file and after parsing its content print the name of the file:
files: [%test1.txt %test2.txt]
rule: [to "test" thru "test" copy x to "." (print x print file)]
foreach file files [
content: read file
parse [any rule]
]
when executing I have
** Script error: file has no value
How can I bind file var name to the context of rule block program ?
It is also possible to do it this way (put in the RULE literally and let FOREACH to bind it at the right time):
files: [%test1.txt %test2.txt]
rule: [to "test" thru "test" copy x to "." (print x print file)]
foreach file files compose/only/deep [
content: read file
parse content [any (rule)]
]
Just need to bind the rule each iteration:
files: [%test1.txt %test2.txt]
rule: [to "test" thru "test" copy x to "." (print x print file)]
foreach file files [
bind rule 'file
content: read file
parse content [any rule]
]