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
Related
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
$
In Bash, I want to compare the fields of 2 different CSVs (field 2 of file1 and field 3 of file2):
diff <(cut -d, -f2 file1) <(cut -d, -f3 file2)
I tried to implement this more generally in Ruby:
def identical_files?(file1, field1, file2, field2)
%x{diff <(cut -d, -f#{field1} #{file1}) <(cut -d, -f#{field2} #{file2})}.blank?
end
Printing the output of the %x{} block, I see sh: Syntax error: "(" unexpected. Does I/O redirection not work when running shell commands within Ruby? Is this because it's only supported by bash but not sh?
It doesn’t work because, as the error you’re getting indicates, Ruby shells out to sh, not Bash. And, of course, sh does not support that syntax.
You can instead call Bash explicitly:
`bash -c 'cat <(echo foo)'` #=> "foo"
Is this because it's only supported by bash but not sh?
Yes.
Process substitution is not supported by sh, even when sh is actually bash (for compatibility).
Don't try to use something as simple as cut to process fields in a CSV file. CSV files can have embedded commas inside fields, which will fool cut, causing your code to do the wrong thing.
Instead, use something designed specifically to process CSV files, such as Ruby's CSV class. Something like this untested code will get you started:
require 'csv'
csv_file1 = CSV.open('file1')
csv_file2 = CSV.open('file2')
until (csv_file1.eof? || csv_file2.eof?) do
row1 = csv_file1.shift
row2 = csv_file2.shift
# do something to diff the fields
puts "#{ csv_file1.lineno }: #{ row1[1] } == #{ row2[2] } --> #{ row1[1] == row2[2] }"
end
[
[csv_file1, 'file1'],
[csv_file2, 'file2']
].each do |f, fn|
puts "Hit EOF for #{ fn }" if f.eof?
f.close
end
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!
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