Why does my IO.write insert a "%" sign at the end of output? - ruby

I use this line to read from temp.dat, which contains "100"
fahrenheit = IO.read("temp.dat").to_i * 9 / 5 + 32
Now, to write this result in another file;
Method 1
f = File.new("temp.out", "w")
f.puts fahrenheit
cat temp.out
212
Method 2
IO.write("temp.out", fahrenheit)
cat temp.out
212%

Why does my IO.write insert a “%” sign at the end of output?
It doesn't. Here's the binary content of the file. That % character is the command prompt of your shell, which is confused by the lack of EOL in the file. POSIX-compliant text files should always end lines with end-of-line character.

Related

How to save chunk of information between two words to a file?

I have a following file:
old_file
new_file
Some string.
end
Text in the middle that is not supposed to go to any of files.
new_file
Another text.
end
How using regex can I create two files with the following content:
file1
new_file
Some string.
end
file2
new_file
Another text.
end
How can I get information which is between keywords 'new_file' and 'end' to write it to the file?
If your files are not that large, you can read them in as a string, (use File.read(file_name)), and then run the following regex:
file_contents.scan(/^new_file$.*?^end$/m).select { |block| WRITE_TO_FILE_CODE_HERE }
See the regex demo
The ^new_file$.*?^end$ regex matches new_file that is a whole line content, then 0+ any characters as few as possible (incl. a newline as /m modifier is used), and then end (a whole line).
Else, you may adapt this answer here as
printing = false
File.open(my_file).each_line do |line|
printing = true if line =~ /^new_file$/
puts line if printing
printing = false if line =~ /^end$/
end
Open the file when the starting line is found, write to it where puts line is in the example above, and close when printing false occurs.
You can also read the file chunk by chunk by changing what constitutes a "line" in ruby:
File.open("file1.txt", "w") do |file1|
File.open("file2.txt", "w") do |file2|
enum = IO.foreach("old_file.txt", sep="\n\n")
file1.puts enum.next.strip
enum.next #discard
file2.puts enum.next.strip
end #automatically closes file2
end #automatically closes file1
By designating the separator as "\n\n" ruby will read all the characters up to and including two consecutive newlines--and return that as a "line".
If that kind of format is fixed, then you may try this (new_file\n.*\nend)

Read files line by line with \r, \n or \r\n as line separator

I want to process files line by line. However, these files have different line separators: "\r", "\n" or "\r\n". I don't know which one they use or which kind of OS they come from.
I have two solutions:
using bash command to translate these separators to "\n".
cat file |
tr '\r\n' '\n' |
tr '\r' '\n' |
ruby process.rb
read the whole file and gsub these separators
text=File.open('xxx.txt').read
text.gsub!(/\r\n?/, "\n")
text.each_line do |line|
do some thing
end
but the second solution is not good when the file is huge. See reference. Is there any other ruby idiomatic and efficient solution?
I suggest you first determine the line separator. I've assumed that you can do that by reading characters until you encounter "\n" or "\r" (or reach the end of the file, in which case we can regard "\n" as the line separator). If the character "\n" is found, I assume that to be the separator; if "\r" is found I attempt to read the next character. If I can do so and it is "\n", I return "\r\n" as the separator. If "\r" is the last character in the file or is followed by a character other than "\n", I return "\r" as the separator.
def separator(fname)
f = File.open(fname)
enum = f.each_char
c = enum.next
loop do
case c[/\r|\n/]
when "\n" then break
when "\r"
c << "\n" if enum.peek=="\n"
break
end
c = enum.next
end
c[0][/\r|\n/] ? c : "\n"
end
Then process the file line-by-line
def process(fname)
sep = separator(fname)
IO.foreach(fname, sep) { |line| puts line }
end
I haven't converted "\r" or "\r\n" to "\n", but of course you could do that easily. Just open a file for writing and in process read each line and write it to the output file with the default line separator.
Let's try it (for clarity I show the value returned by separator):
fname = "temp"
IO.write(fname, "slash n line 1\nslash n line 2\n")
#=> 30
separator(fname)
#=> "\n"
process(fname)
# slash n line 1
# slash n line 2
IO.write(fname, "slash r line 1\rslash r line 2\r", )
#=> 30
separator(fname)
#=> "\r"
process(fname)
# slash r line 1
# slash r line 2
IO.write(fname, "slash r slash n line 1\r\nslash r slash n line 2\r\n")
#=> 48
separator(fname)
#=> "\r\n"
process(fname)
# slash r slash n line 1
# slash r slash n line 2

grep the input file with keyword, then generate new report

cat infile
abc 123 678
sda 234 345 321
xyz 234 456 678
I need grep the file for keyword sda and report with first and last column.
sda has the value of 321
If you know bash script, I need a function in ruby as in below bash(awk) script:
awk '/sda/{print $1 " has the value of " $NF}' infile
How about something like this?
File.open("infile", "r").each_line do |line|
next unless line =~ /^sda/ # don't process the line unless it starts with "sda"
entries = line.split(" ")
var1 = entries.first
var2 = entries.last
puts "#{var1} has the value of #{var2}"
end
I don't know where you are defining the "sda" matcher. If it's fixed, you can just put it in there.
If not, you might try grabbing it from commandline arguments.
key, *_, value = line.split
next unless key == 'sda' # or "next if key != 'sda'"
puts your_string
Alternatively, you could use a regexp matcher in the beginning to see if the line starts with 'sda' or not.

How do I join two lines of a file by matching pattern, in Ruby or Bash?

I'm using a Ruby script to do a lot of manipulation and cleaning to get this, and a bunch of other files, ready for import.
I have a really large file with some data that I'm trying to import into a database. There are some data issues with newline characters being in the data where they should not be, messing with the import.
I was able to solve this problem with sed using this:
sed -i '.original' -e ':a' -e 'N' -e '$!ba' -e 's/Oversight Bd\n/Oversight Bd/g' -e 's/Sciences\n/Sciences/g' combined_old_individual.txt"
However, I can't call that command from inside a Ruby script, because Ruby messes up interpreting the newline characters and won't run that command. sed needs the non-escaped newline character but when calling a system command from Ruby it needs a string, where the newline character needs to be escaped.
I also tried doing this using Ruby's file method, but it's not working either:
File.open("combined_old_individual.txt", "r") do |f|
File.open("combined_old_individual_new.txt","w") do |new_file|
to_combine = nil
f.each_line do |line|
if(/Oversight Bd$/ =~ line || /Sciences$/ =~ line)
to_combine = line
else
if to_combine.nil?
new_file.puts line
else
combined_line = to_combine + line
new_file.puts combined_line
to_combine = nil
end
end
end
end
end
Any ideas how I can join lines where the first line ends with "Bd" or "Sciences", from within a Ruby script, would be very helpful.
Here's an example of what might go in a testfile.txt:
random line
Oversight Bd
should be on the same line as the above, but isn't
last line
and the result should be
random line
Oversight Bdshould be on the same line as the above, but isn't
last line
With ruby (My first attempt at a ruby answer):
File.open("combined_old_individual.txt", "r") do |f|
File.open("combined_old_individual_new.txt","w") do |new_file|
f.each_line do |line|
if(/(Oversight Bd|Sciences)$/ =~ line)
new_file.print line.strip
else
new_file.puts line
end
end
end
end
You have to realize that sed normally works line by line, so you cannot match for \n in your initial pattern. You can however match for the pattern on the first line and then pull in the next line with the N command and then run the substitute command on the buffer to remove the newline like so:
sed -i -e '/Oversight Bd/ {;N;s/\n//;}' /your/file
Run from Ruby (without -i so that the output goes to stdout):
> cat test_text
aaa
bbb
ccc
aaa
bbb
ccc
> cat test.rb
cmd="sed -e '/aaa/ {;N;s/\\n//;}' test_text"
system(cmd)
> ruby test.rb
aaabbb
ccc
aaabbb
ccc
Since you are asking in bash, here is a pure-bash solution:
$ r="(Oversight Bd|Sciences)$"
$ while read -r; do printf "%s" "$REPLY"; [[ $REPLY =~ $r ]] || echo; done < combined_old_individual.txt
random line
Oversight Bdshould be on the same line as the above, but isn't
last line
$

Reading from stdin and printing to stdout in Ruby

This question is kinda simple (don't be so harsh with me), but I can't get a code-beautiful solution. I have the following code:
ARGF.each_line do |line|
arguments = line.split(',')
arguments.each do |task|
puts "#{task} result"
end
end
It simply read from the standard input numbers. I use it this way:
echo "1,2,3" | ruby prog.rb
The output desired is
1 result
2 result
3 result
But the actual output is
1 result
2 result
3
result
It seems like there's a newline character introduced. I'm skipping something?
Each line ends in a newline character, so splitting on commas in your example means that the last token is 3\n. Printing this prints 3 and then a newline.
Try using
arguments = line.chomp.split(',')
To remove the trailing newlines before splitting.
Your stdin input includes a trailing newline character. Try calling line.chomp! as the first instruction in your each_line block.

Resources