I have Ruby code similar to:
ok.rb
hasil = "input operator salah"
puts hasil
exec("sort ok.rb > output.txt") if fork.nil?
It just wrote all code into output.txt. However, I only want hasil result to be written to output.txt. How should I modify the code for such an end result?
You've executed the sort command taking ok.rb as the input. Instead, you want to run ok.rb and take its output as the input to sort.
Without knowing Ruby, I'd expect this to be something like:
exec("ruby ok.rb | sort > output.txt") if fork.nil?
I've just tried this from my Linux desktop and it worked fine:
ok.rb:
hasil = "input operator salah"
puts hasil
other.rb:
exec("ruby ok.rb | sort > output.txt") if fork.nil?
Execute:
$ ruby other.rb
$ cat output.txt
input operator salah
(You've only provided a single line of output so there wasn't exactly a lot to sort.)
The cleanest way would be to change the preceding code to not produce output to stdout directly, but instead to only build the string and then sort this from ruby and print it to the file. Like this for example:
hasil = "input operator salah"
File.open("output.txt", "w") do |f|
f.puts hasil.split("\n").sort.join("\n")
end
If replacing unix sort with ruby sort is not an option (maybe because sort was just an example and in reality you're piping to a different application that can't easily be replaced with ruby), you can write your code to the application directly instead of writing to stdout. You could even write your code to be general enough to write to any IO.
def generate_output(out)
hasil = "input operator salah"
out.puts hasil
end
# If you decide to output the text directly to stdout (without sorting)
generate_output(stdout)
# If you instead want to pipe to sort:
IO.popen("sort > output.txt", "w") do |sort|
generate_output(sort)
end
Related
Im triying to use this code but not work
ruby -a -F';' -ne if $F[2]<4 'puts $F[3]' ppp.txt
this is my file
mmm;2;nsfnjd
sadjjasjnsd;6;gdhjsd
gsduhdssdj;3;gsdhjhjsd
what is doing worng Please help me
First of all, instead of treating Ruby like some kind of fancy Perl and writing scripts like that, let's expand it into the Ruby code equivalent for clarity:
$; = ';'
while gets
$F = $_.split
if $F[2]<4
puts $F[3]
end
end
Your original code doesn't work, it can't possibly work because it's not valid Ruby code, and further, you're not properly quoting it to pass through the -e evaluation term. Trying to run it I get:
-bash: 4: No such file or directory
You're also presuming the array is 1-indexed, but it's not. It's 0-indexed. Additionally Ruby treats integer values as completely different from strings, never equivalent, not auto-converted. As such you need to call .to_i to convert.
Here's a re-written program that does the job:
File.open(ARGV[0]) do |fi|
fi.readlines.each do |line|
parts = line.chomp.split(';')
if parts[1].to_i < 4
puts parts[2]
end
end
end
I solved with this
ruby -a -F';' -ne ' if $F[1] < "4" ;puts $F[2] end ' ppp.txt
I have many text files containing annotations. The original text is marked with lines containing the words:
START OF TEXT OF PASSAGE 1
END OF TEXT OF PASSAGE 1
Obviously I can search each document for the phrase START OF TEXT and delete everything up to it. Then search for END OF TEXT and start selecting text for deletion until I get to the next START OF TEXT.
I have come up with this design so far:
#!/bin/bash
a="START OF PROJECT"
b="END OF PROJECT"
while read line; do
if line contains a; do
while read line; do
'if line does not contain b'
'append the line to output.txt'; fi
done
done
fi
done
Perhaps there is an easier way using sed, awk, grep and pipes?
'for every document' 'loop through it doing this' ('find the original text between START and END' | >> output.txt)
Unfortunately I am poor at bash and ignorant of sed/awk.
The reason for this is that I am assembling a huge text document that is a concatenation of thousands of marked up documents – each of which contains some annotated passages.
In Python:
import re
with open('in.txt') as f, open('out.txt', 'w') as output:
output.write('\n'.join(re.findall(r'START OF TEXT(.*?)END OF TEXT', f.read())))
This reads the input, searches for all matches that begin and end with the necessary markers, captures the text of interest in a group, joins all those groups on a linefeed, and writes that to the result file.
Pretty easy to do with awk. You would create a script (I'll call it yank.awk) containing this:
#!/usr/bin/awk
/START OF PROJECT/ { capture = 1; next }
/END OF PROJECT/ { capture = 0 }
capture == 1 { print }
and then run it like so:
yank.awk in.txt > output.txt
Could also do with sed and grep:
sed -ne '/START OF PROJECT/,/END OF PROJECT/p' in.txt | grep -vE '(START|END) OF PROJECT' > output.txt
(Another Python solution)
You can have itertools.groupby group lines together based on a boolean value - just use a global flag to keep track of whether you are in a block or not, and then use groupby to group the lines that are in or out of blocks. Then just discard the ones that are not blocks:
sample_lines = """
lskdjflsdkjf
sldkjfsdlkjf
START OF TEXT
Asdlkfjlsdkfj
Bsldkjf
Clsdkjf
END OF TEXT
sldkfjlsdkjf
sdlkjfdklsjf
sdlkfjdlskjf
START OF TEXT
Dsdlkfjlsdkfj
Esldkjf
Flsdkjf
END OF TEXT
sldkfjlsdkjf
sdlkjfdklsjf
sdlkfjdlskjf
""".splitlines()
from itertools import groupby
in_block = False
def is_in_block(line):
global in_block
if line.startswith("END OF TEXT"):
in_block = False
ret = in_block
if line.startswith("START OF TEXT"):
in_block = True
return ret
for lines_are_text,lines in groupby(sample_lines, key=is_in_block):
if lines_are_text:
print(list(lines))
gives:
['Asdlkfjlsdkfj', 'Bsldkjf', 'Clsdkjf']
['Dsdlkfjlsdkfj', 'Esldkjf', 'Flsdkjf']
See that first group has the lines that start with A, B, and C, and the second group is made up of those lines starting with D, E, and F.
It sounds like the specific solution you need is:
awk '/END OF TEXT OF PASSAGE/{f=0} f; /START OF TEXT OF PASSAGE/{f=1}' file
See https://stackoverflow.com/a/18409469/1745001 for other ways to select text from files.
Use Perl's Flip-Flop Operator to Print Text Between Markers
Given a corpus like:
START OF TEXT OF PASSAGE 1
foo
END OF TEXT OF PASSAGE 1
START OF TEXT OF PASSAGE 2
bar
END OF TEXT OF PASSAGE 2
you can use the Perl flip-flop operator to process within a range of lines. For example, from the shell prompt:
$ perl -ne 'if (/^START OF TEXT/ ... /^END OF TEXT/) {
next if /^(?:START|END)/;
print;
}' /tmp/corpus
foo
bar
Basically, this short Perl script loops through your input. When it finds your start and end tags, it throws away the tags themselves and prints everything else in between.
Usage Notes
The line breaks between passages in the corpus are for readability. It doesn't matter if your real corpus has no line breaks between passages, so long as the text markers always start at the beginning of the line as shown in your original post. If that assumption doesn't hold true, then you will need to adjust the regular expressions used to identify the start and end of your passages.
You can pass multiple files to the Perl script. Again, it makes no practical difference as long as you don't exceed the length limit of your shell.
If you want the final output to go to somewhere other than standard output, just use shell redirection. For example:
perl -ne 'if (/^START OF TEXT/ ... /^END OF TEXT/) {
next if /^(?:START|END)/;
print;
}' /tmp/file1 /tmp/file2 /tmp/file3 > /tmp/output
You can use sed as follows:
sed -n '/^START OF TEXT/,/^END OF TEXT/{/^\(START\|END\) OF TEXT/!p}' infile
or, with extended regular expressions (-r):
sed -rn '/^START OF TEXT/,/^END OF TEXT/{/^(START|END) OF TEXT/!p}' infile
-n prevents sed from printing as a default. The rest works as follows:
/^START OF TEXT/,/^END OF TEXT/ { # For lines between these two matches
/^\(START\|END\) OF TEXT/!p # If the line does NOT match, print it
}
This works with GNU sed and might require some tweaking to run with other seds.
How would i put line breaks in between lines like this:
print "Hi"
print "Hi"
Because it would just output this:
HiHi
Use puts since it will automatically add a newline for you:
puts "Hi"
puts "Hi"
If you want to make an explicit newline character then you'll need to know what kind of system(s) on which your program will run:
print "Hi\n" # For UNIX-like systems including Mac OS X.
print "Hi\r\n" # For Windows.
Use line break character:
print "Hi\n"
print "Hi"
puts "\n" works also on Win/Ruby ruby 2.4.2p198
and even "\n"*4 for multiplication of new rows (by 4)
You can create a space by adding a string with only a space in it between the 2 other strings. For example:
print "Hi" + " " + "Hi"
You could avoid the two print statements and instead only use one line.
print "Hi\r\nHi"
Or if you want to use two lines then
print "Hi\r\n"
print "Hi"
I am new to Ruby. I have used shell in the past. I am converting a shell program to ruby. I have the following command
cmd="cat -n " + infile + " | grep '127.0.0.1 '" + site
f = %x[#{cmd}]
The shell cat command returns the line I am looking for and the line number. I would like to be able to do something similar in ruby without using shell. May need to port this program to windows. I can use the grep function in ruby but how do I return the line number without having to loop through a million lines in a file. Thanks.
Here's a little ruby function that'll do what you're asking for. You do have to loop through each line, but grep was doing that too - you just didn't have to do it yourself. Fortunately, ruby makes looping easy:
def mygrep(filename, regex)
result = []
File.open(filename) do |f|
f.each_with_index do |l, i|
result << [i, l] if regex =~ l
end
end
return result
end
Cheers!
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
The community reviewed whether to reopen this question last month and left it closed:
Original close reason(s) were not resolved
Improve this question
I want to deal with the command line input in Ruby:
> cat input.txt | myprog.rb
> myprog.rb < input.txt
> myprog.rb arg1 arg2 arg3 ...
What is the best way to do it? In particular I want to deal with blank STDIN, and I hope for an elegant solution.
#!/usr/bin/env ruby
STDIN.read.split("\n").each do |a|
puts a
end
ARGV.each do |b|
puts b
end
Following are some things I found in my collection of obscure Ruby.
So, in Ruby, a simple no-bells implementation of the Unix command
cat would be:
#!/usr/bin/env ruby
puts ARGF.read
— https://web.archive.org/web/20080725055721/http://www.oreillynet.com/ruby/blog/2007/04/trivial_scripting_with_ruby.html#comment-565558
ARGF is your friend when it comes to input; it is a virtual file that gets all input from named files or all from STDIN.
ARGF.each_with_index do |line, idx|
print ARGF.filename, ":", idx, ";", line
end
# print all the lines in every file passed via command line that contains login
ARGF.each do |line|
puts line if line =~ /login/
end
Thank goodness we didn’t get the diamond operator in Ruby, but we did
get ARGF as a replacement. Though obscure, it actually turns out to
be useful. Consider this program, which prepends copyright headers
in-place (thanks to another Perlism, -i) to every file mentioned on
the command-line:
#!/usr/bin/env ruby -i
Header = DATA.read
ARGF.each_line do |e|
puts Header if ARGF.pos - e.length == 0
puts e
end
__END__
#--
# Copyright (C) 2007 Fancypants, Inc.
#++
— http://blog.nicksieger.com/articles/2007/10/06/obscure-and-ugly-perlisms-in-ruby
Credit to:
https://web.archive.org/web/20080725055721/http://www.oreillynet.com/ruby/blog/2007/04/trivial_scripting_with_ruby.html#comment-565558
http://blog.nicksieger.com/articles/2007/10/06/obscure-and-ugly-perlisms-in-ruby
Ruby provides another way to handle STDIN: The -n flag. It treats your entire program as being inside a loop over STDIN, (including files passed as command line args). See e.g. the following 1-line script:
#!/usr/bin/env ruby -n
#example.rb
puts "hello: #{$_}" #prepend 'hello:' to each line from STDIN
#these will all work:
# ./example.rb < input.txt
# cat input.txt | ./example.rb
# ./example.rb input.txt
I am not quite sure what you need, but I would use something like this:
#!/usr/bin/env ruby
until ARGV.empty? do
puts "From arguments: #{ARGV.shift}"
end
while a = gets
puts "From stdin: #{a}"
end
Note that because ARGV array is empty before first gets, Ruby won't try to interpret argument as text file from which to read (behaviour inherited from Perl).
If stdin is empty or there is no arguments, nothing is printed.
Few test cases:
$ cat input.txt | ./myprog.rb
From stdin: line 1
From stdin: line 2
$ ./myprog.rb arg1 arg2 arg3
From arguments: arg1
From arguments: arg2
From arguments: arg3
hi!
From stdin: hi!
Something like this perhaps?
#/usr/bin/env ruby
if $stdin.tty?
ARGV.each do |file|
puts "do something with this file: #{file}"
end
else
$stdin.each_line do |line|
puts "do something with this line: #{line}"
end
end
Example:
> cat input.txt | ./myprog.rb
do something with this line: this
do something with this line: is
do something with this line: a
do something with this line: test
> ./myprog.rb < input.txt
do something with this line: this
do something with this line: is
do something with this line: a
do something with this line: test
> ./myprog.rb arg1 arg2 arg3
do something with this file: arg1
do something with this file: arg2
do something with this file: arg3
while STDIN.gets
puts $_
end
while ARGF.gets
puts $_
end
This is inspired by Perl:
while(<STDIN>){
print "$_\n"
}
Quick and simple:
STDIN.gets.chomp == 'YES'
You can also use STDIN.each_line, and STDIN.each_line.to_a to get it as an array.
e.g.
STDIN.each_line do |line|
puts line
end
I'll add that in order to use ARGF with parameters, you need to clear ARGV before calling ARGF.each. This is because ARGF will treat anything in ARGV as a filename and read lines from there first.
Here's an example 'tee' implementation:
File.open(ARGV[0], 'w') do |file|
ARGV.clear
ARGF.each do |line|
puts line
file.write(line)
end
end
I do something like this :
all_lines = ""
ARGV.each do |line|
all_lines << line + "\n"
end
puts all_lines
It seems most answers are assuming the arguments are filenames containing content to be cat'd to the stdin. Below everything is treated as just arguments. If STDIN is from the TTY, then it is ignored.
$ cat tstarg.rb
while a=(ARGV.shift or (!STDIN.tty? and STDIN.gets) )
puts a
end
Either arguments or stdin can be empty or have data.
$ cat numbers
1
2
3
4
5
$ ./tstarg.rb a b c < numbers
a
b
c
1
2
3
4
5