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
| #!/usr/bin/env perl
use strict;
use warnings;
use Getopt::Long;
use Text::CSV;
my $input;
my $output;
my $delimiter = ',';
my $columns;
my $filter;
GetOptions(
'input|i=s' => \$input,
'output|o=s' => \$output,
'delimiter|d=s' => \$delimiter,
'columns|c=s' => \$columns,
'filter|f=s' => \$filter,
) or die "Error in arguments\n";
die "Error: --input is required\n" unless $input;
my $csv = Text::CSV->new({ sep_char => $delimiter });
open my $in_fh, '<', $input or die "Cannot open $input: $!\n";
my $out_fh;
if ($output) {
open $out_fh, '>', $output or die "Cannot open $output: $!\n";
} else {
$out_fh = \*STDOUT;
}
# 列の選択
my @select_columns;
if ($columns) {
@select_columns = split /,/, $columns;
}
# フィルター式(安全な実装例)
# evalは任意のコード実行を許可するため、本番環境では使用しない
# 代わりに、安全な比較演算子のみをサポートする実装を推奨
my $filter_sub;
if ($filter) {
# 注意: evalは危険!実際の運用では使用しない
# この例は学習目的のみ。本番では列名、演算子、値を個別に受け取る設計に
warn "WARNING: eval is dangerous! Use --column, --operator, --value instead\n";
# より安全な代替案: 特定のパターンのみ許可
# 例: --column 2 --op '>' --value 100
# こうすれば任意のコード実行を防げる
# 以下は教育目的のデモコード(本番では使用禁止)
$filter_sub = eval "sub { my \$row = shift; $filter }";
die "Filter error: $@" if $@;
}
my $header = $csv->getline($in_fh);
while (my $row = $csv->getline($in_fh)) {
# フィルター適用
next if $filter_sub && !$filter_sub->($row);
# 列の選択
if (@select_columns) {
my @selected = @{$row}[@select_columns];
$csv->print($out_fh, \@selected);
print $out_fh "\n";
} else {
$csv->print($out_fh, $row);
print $out_fh "\n";
}
}
close $in_fh;
close $out_fh if $output;
# より安全なフィルター実装例(推奨):
# GetOptions(
# 'filter-column=i' => \my $filter_col,
# 'filter-op=s' => \my $filter_op, # eq, ne, >, <, >=, <=
# 'filter-value=s' => \my $filter_val,
# );
#
# my %safe_ops = (
# 'eq' => sub { $_[0] eq $_[1] },
# 'ne' => sub { $_[0] ne $_[1] },
# '>' => sub { $_[0] > $_[1] },
# '<' => sub { $_[0] < $_[1] },
# );
#
# my $op_sub = $safe_ops{$filter_op};
# next if $filter_col && !$op_sub->($row->[$filter_col], $filter_val);
|