-
Notifications
You must be signed in to change notification settings - Fork 0
/
adjoin
executable file
·148 lines (121 loc) · 2.49 KB
/
adjoin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#!/usr/bin/env ruby
# Andy's Join: join lines in streams by separator.
require 'optparse'
# List of single character escape sequences
ESCAPES = {
"\\\\" => "\\",
'\a' => "\a",
'\b' => "\b",
'\e' => "\e",
'\f' => "\f",
'\n' => "\n",
'\r' => "\r",
'\s' => "\s",
'\t' => "\t",
'\v' => "\v",
}
# There has to be a better way to do this.
def apply_backslash_escapes(string)
string = string.dup
string.gsub!(/\\(\\|[abefnrstv]|0\d{1,3}|x\h{1,2}|\d{1,3})/) do |matched|
captured = $1
if ESCAPES.include?(matched)
ESCAPES.fetch(matched)
else
if captured =~ /\A\d{1,3}\z/
num = Integer(captured, 8)
num.chr
else
case captured[0]
when '0'
num = Integer(captured[1..-1], 8)
num.chr
when 'x'
num = Integer(captured[1..-1], 16)
num.chr
else
raise "Unexpected escape: #{matched.inspect}"
end
end
end
end
string
end
def adjoin(sep, *streams)
first_stream = true
streams.each do |stream|
if first_stream
first_stream = false
else
print sep
end
begin
print stream.readline.chomp
rescue EOFError
# ignore
end
stream.each_line do |line|
print sep
print line.chomp
end
end
print "\n"
end
def main
options = {}
optparse = OptionParser.new do |opts|
opts.banner = <<-EOM
usage: #{File.basename($0)} [OPTIONS] SEPARATOR [FILE...]
Join each line in each FILE by SEPARATOR. If no FILE is not given, read from
standard input.
For example:
$ seq 1 10 | adjoin ,
1,2,3,4,5,6,7,8,9,10
$ seq 1 5 | adjoin -e '\\t'
1\t2\t3\t4\t5
$ adjoin - 1to5.txt 6to10.txt
1-2-3-4-5-6-7-8-9-10
Options:
EOM
opts.on('-h', '--help', 'Display this message') do
puts opts
exit
end
opts.on('-e', '--escape',
'Enable interpretation of backslash escapes (buggy)') do
options[:escapes] = true
end
opts.on('-0', '--null', 'Use a separator of NUL') do
options[:null] = true
end
end
optparse.parse!
if options[:null]
sep = "\0"
else
sep = ARGV.shift
end
if sep.nil?
puts optparse
exit 1
end
if options[:escapes]
sep = apply_backslash_escapes(sep)
end
if ARGV.empty?
streams = [STDIN]
else
streams = ARGV.map {|filename|
if filename == '-'
STDIN
else
File.open(filename, 'r')
end
}
end
adjoin(sep, *streams)
0
end
if $0 == __FILE__
exit main
end