How to delete lines from file without create a temporary file in ruby? - ruby

I need delete line of a file sequentially with ruby, but without success.
If i open the file with w+ flag, it gets completely empty, and if i open with r+ flag, nothing happens.
I even tried do it with by sed's system command, without results too.
What's wrong?
$ cat teste.txt
foo
bar
- This is by ruby way:
$ cat ruby.rb
#!/usr/bin/ruby
path = '/home/paulosgf/hack/metasploit/teste.txt'
File.open(path, 'r+') do |file|
file.each do |line|
puts(line)
line.gsub(/^.$\n/, '')
end
file.close()
end
$ ./ruby.rb
foo
bar
$ cat teste.txt (nothing happens)
foo
bar
- This is by sed way:
$ cat sed.rb
#!/usr/bin/ruby
path = '/home/paulosgf/hack/metasploit/teste.txt'
File.open(path, 'r+') do |file|
file.each do |line|
puts(line)
system("sed -i", "/#{line}/d #{path}")
end
file.close()
end
$ ./sed.rb
foo
bar
$ cat teste.txt
foo
bar
I need get the next line, run some processing and delete these line at end, but all lines remains on file yet.

i found the solution on another forum.
[https://www.ruby-forum.com/t/delete-first-line-of-a-text-file/134316/4]
It only needed to change the focus:
[ paulosgf /home/paulosgf/hack/metasploit ] $ cat teste.txt
john
doe
foo
bar
[ paulosgf /home/paulosgf/hack/metasploit ] $ cat delFirst.rb
#!/usr/bin/ruby
path = '/home/paulosgf/hack/metasploit/teste.txt'
remains=''
line=''
each=''
File.foreach(path) { |each|
File.open(path, 'r') {|file| line=file.gets; remains=file.read}
puts("#{line}")
File.open(path, 'w+') {|file| file.write(remains)}
}
[ paulosgf /home/paulosgf/hack/metasploit ] $ ./delFirst.rb
john
doe
foo
bar
[ paulosgf /home/paulosgf/hack/metasploit ] $ cat teste.txt
[ paulosgf /home/paulosgf/hack/metasploit ] $

Related

Display Unique Shell Columns

Given we have two formatted strings that are unrelated to each other.
#test.rb
string_1 = "Title\nfoo bar\nbaz\nfoo bar baz boo"
string_2 = "Unrelated Title\ndog cat farm\nspace moon"
How can I use ruby or call shell commands to have each of these string display as columns in terminal? The key is that the data of each string are not building a correlated row, ie this is not a table, rather 2 lists side by side.
Title Unrelated Title
foo bar dog cat farm
baz space moon
foo bar baz boo
You can try using paste and column command together. Note that this is a shell command so spaces between the assignment operator should be corrected.
$ string_1="Title\nfoo bar\nbaz\nfoo bar baz boo"
$ string_2="Unrelated Title\ndog cat farm\nspace moon"
$ paste -d '|' <(echo -e "$string_1") <(echo -e "$string_2") | column -s'|' -t
Title Unrelated Title
foo bar dog cat farm
baz space moon
foo bar baz boo
We paste the lines with | as delimiter and tell column command to use | as a reference to form columns.
In Ruby, you could do it this way:
#!/usr/bin/env ruby
string_1 = "Title\nfoo bar\nbaz\nfoo bar baz boo"
string_2 = "Unrelated Title\ndog cat farm\nspace moon"
a1 = string_1.split("\n")
a2 = string_2.split("\n")
a1.zip(a2).each { |pair| puts "%-20s%s" % [pair.first, pair.last] }
# or
# a1.zip(a2).each { |left, right| puts "%-20s%s" % [left, right] }
This produces:
Title Unrelated Title
foo bar dog cat farm
baz space moon
foo bar baz boo
Hi , If you Use temp files
string_1 = "Title\nfoo bar\nbaz\nfoo bar baz boo"
string_2 = "Unrelated Title\ndog cat farm\nspace moon"
echo -e $string_1 >a.txt
echo -e $string_2 >b.txt
paste a.txt b.txt
I hope it will help.

How to write pattern for rename in Ruby?

I have several files of this type:
File-1 (vip)-eojUBB_8V_4.mp4
File-2 (vip)-Ek2iyeeL1Vc.mp4
File-3 (vip)-Gh8F6OJa0gU.mp4
File-4 (vip)-SvL_aZt3zyU.mp4
and wanna rename file to:
File-1.mp4
File-2.mp4
Names "File1" and "File2" are just a example. Actually files have a different names but with "(vip)-smthing.mp4" in the end of filename.
I wrote the script:
#!/usr/bin/env ruby
require 'fileutils'
list = %x(ls -1 | grep .mp4).split(",")
list.each do |i|
File.rename(i, i.gsub(/(vip)*.mp4/, ".mp4"))
end
but can't understand, what pattern I need to write inside gsub.
Bash example work's fine, but i need to write it on Ruby.
ls -1 | sed 's/-[^-]\+\././'
#!/usr/bin/env ruby
require 'fileutils'
list = Dir.glob('*.mp4')
list.each do |src|
if src =~ /^(File\d+)/
dst = "#{$1}.mp4"
puts "renaming '#{src}' to '#{dst}'"
File.rename(src, dst)
end
end
Output:
$ ls
File1 (vip)-dHsq8aF2P0U.mp4 File2 (vip)-asdfsad.mp4 foo.rb
$ ruby foo.rb
renaming 'File1 (vip)-dHsq8aF2P0U.mp4' to 'File1.mp4'
renaming 'File2 (vip)-asdfsad.mp4' to 'File2.mp4'
$ ls
File1.mp4 File2.mp4 foo.rb
The answer is:
#!/usr/bin/env ruby
require 'fileutils'
list = %x(ls -1 | grep .mp4).split(",")
list.each do |i|
puts i.gsub(/ \(vip\)-\S+\./, ".")
end
Thanks to Philip Hallstrom and http://rubular.com/

How to check ARGF is empty or not in Ruby

I want to do with ARGF like this.
# file.rb
if ARGF.???
puts ARGF.read
else
puts "no redirect."
end
$ echo "Hello world" | ruby file.rb
Hello world
$ ruby file.rb
no redirect.
I need to do without waiting user input. I tried eof? or closed? doesn't help. Any ideas?
NOTE I was misunderstood ARGF. please see comments below.
Basically you'd examine #filename. One way to do this is:
if ARGF.filename != "-"
puts ARGF.read
else
puts "no redirect."
end
And this is the more complete form:
#!/usr/bin/env ruby
if ARGF.filename != "-" or (not STDIN.tty? and not STDIN.closed?)
puts ARGF.read
else
puts "No redirect."
end
Another:
#!/usr/bin/env ruby
if not STDIN.tty? and not STDIN.closed?
puts STDIN.read
else
puts "No redirect."
end
There might be a better way, but for me I needed to read the contents of a files being passed as arguments as well as having a files contents redirected to stdin.
my_executable
#!/usr/bin/env ruby
puts ARGF.pos.zero?
Then
$ my_executable file1.txt # passed as argument
#=> true
$ my_executable < file1.txt # redirected to stdin
#=> true
$ my_executable
#=> false
So I took all three currently suggested solutions:
p (not STDIN.tty? and not STDIN.closed?)
p ARGF.filename
p ARGF.pos
and saw that none of them actually works:
$ ruby temp.rb
false
"-"
36471287
$ ruby temp.rb temp.rb
false
"temp.rb"
0
$ echo 123 | ruby temp.rb
true
"-"
temp.rb:3:in `pos': Illegal seek # rb_io_tell - <STDIN> (Errno::ESPIPE)
from temp.rb:3:in `<main>'
because to assume the ability to call the ARGF.read you want to get false/true/true.
So I suppose you have to combine them:
!STDIN.tty? && !STDIN.closed? || ARGF.filename != ?-

How do I write one-liner script that inserts the contents of one file to another file?

Say I have file A, in middle of which have a tag string "#INSERT_HERE#". I want to put the whole content of file B to that position of file A. I tried using pipe to concatenate those contents, but I wonder if there is more advanced one-line script to handle it.
$ cat file
one
two
#INSERT_HERE#
three
four
$ cat file_to_insert
foo bar
bar foo
$ awk '/#INSERT_HERE#/{while((getline line<"file_to_insert")>0){ print line };next }1 ' file
one
two
foo bar
bar foo
three
four
cat file | while read line; do if [ "$line" = "#INSERT_HERE#" ]; then cat file_to_insert; else echo $line; fi; done
Use sed's r command:
$ cat foo
one
two
#INSERT_HERE#
three
four
$ cat bar
foo bar
bar foo
$ sed '/#INSERT_HERE#/{ r bar
> d
> }' foo
one
two
foo bar
bar foo
three
four

Best practices with STDIN in Ruby? [closed]

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

Resources