基礎
Hello World
use strict/warningsの使用がベストプラクティスです
#!/usr/bin/perl
use strict;
use warnings;
print "Hello, World!\n";
# variables: scalar ($), array (@), hash (%)
my $name = "Alice";
my @nums = (1, 2, 3);
my %ages = (Alice => 30, Bob => 25);
print "Name: $name\n";コメント
=pod =cutで複数行コメント
#!/usr/bin/perl
# This is a single-line comment
print "Hello\n"; # inline comment
=pod
This is a multi-line
comment using POD (Plain Old Documentation)
=cut
print "After POD\n";スクリプトの実行
perlコマンドラインオプション
my $str = "Hello";
my $num = 42;
my $float = 3.14;
my $bool = 1; # true (0, "", "0", undef are false)
# String repetition
my $line = "-" x 20;
# String concatenation
my $greeting = "Hello, " . $str;
print "$greeting\n"; # Hello, Hellosay関数
sayは自動的に改行を追加します
my $name = "Alice";
my $age = 30;
print "Name: $name\n"; # interpolates
print 'Name: $name\n'; # literal (no interpolation)
# Disambiguate variable name with braces
my $fruit = "apple";
print "I have many ${fruit}s.\n"; # I have many apples.
# Array interpolation (joins with $")
my @arr = (1, 2, 3);
print "Array: @arr\n"; # Array: 1 2 3shebang
env perlはよりポータブルです
use strict;
use warnings;
# Without strict, this would create a global:
# $foo = 42; # ERROR under strict
my $foo = 42; # OK with my
# Warnings catch common mistakes
my $undef_var;
# print $undef_var; # warns: uninitialized value
# Modern bundle (v5.36+ enables strict, warnings, features)
use v5.36;
# Disable specific warnings locally
no warnings 'uninitialized';say & features
say is like print but appends a newline. Enable features with 'use feature' or a version bundle like 'use v5.36'. Signatures give named parameters instead of unpacking @_.
use v5.10;
use feature 'say';
say "Hello!"; # adds newline automatically
say "No need for \n";
# Equivalent to:
print "Hello!\n";
# Signatures (v5.20+, not default)
use feature 'signatures';
no warnings 'experimental::signatures';
sub greet ($name) {
say "Hi, $name";
}スカラー
スカラー変数
$プレフィックスはスカラーを示します
my $sum = 5 + 3; # 8
my $diff = 10 - 4; # 6
my $prod = 6 * 7; # 42
my $div = 10 / 3; # 3.3333...
my $int = int(10 / 3); # 3
my $mod = 10 % 3; # 1
my $pow = 2 ** 10; # 1024
# Augmented assignment
my $x = 5;
$x += 3; # $x = 8
$x **= 2; # $x = 64
$x++; # $x = 65
$x--; # $x = 64文字列操作
一般的な文字列関数
my $a = "Hello";
my $b = "World";
# Concatenation
my $combined = $a . ", " . $b; # Hello, World
# Repetition
my $line = "=" x 30;
# Augmented concatenation
my $str = "abc";
$str .= "def"; # abcdef
# Numeric vs string comparison
print "match" if "abc" eq "abc"; # string equal
print "match" if 123 == 123; # numeric equal文字列補間
ダブルクォートは補間し、シングルクォートはしません
my $x; # undef
print "undef\n" if !defined $x;
$x = undef; # explicitly undef
undef $x; # another way
# Defined-or operator
my $val = $x // "default";
# Warning if used as string:
# print $x; # Use of uninitialized value
if (defined $val) {
print "Defined: $val\n";
}数値操作
数値関数
my $name = "Alice";
# q() = single quote (no interpolation)
my $s1 = q(Hello $name); # Hello $name
# qq() = double quote (interpolation)
my $s2 = qq(Hello $name); # Hello Alice
# qw() = quoted words (produces a list)
my @words = qw(apple banana cherry);
# equivalent to ("apple", "banana", "cherry")
# Custom delimiters
my $s3 = q{don't worry};
my $s4 = q!bang!;undef
undefは未定義を意味します
my $name = "Alice";
# Single-quote style (no interpolation)
my $text = <<'END';
Hello $name,
This is literal.
END
# Double-quote style (interpolation)
my $msg = <<"EOF";
Hello $name,
Interpolated here.
EOF
print $msg;
# Indented heredoc (v5.26+)
my $code = <<~EOT;
line 1
line 2
EOTBoolean Truthiness
Only undef, 0, '', and '0' are false; even '00' and '0.0' are true! Use || for truthy defaults and // for defined defaults. References (even empty arrays) are always true.
# False values: undef, 0, "", "0"
# Everything else is true
print "true\n" if 1; # true
print "true\n" if "hello"; # true
print "true\n" if "0"; # NOT printed (false!)
print "true\n" if ""; # NOT printed (false)
print "true\n" if []; # true (reference is true)
# Logical operators
my $x = 0 || "default"; # default (|| tests truthiness)
my $y = 0 // "default"; # default (// tests definedness)
my $z = "a" && "b"; # b (returns last evaluated)配列
配列操作
@プレフィックスは配列、$は要素アクセス
my @nums = (1, 2, 3, 4, 5);
my @strs = qw(a b c);
my @mixed = (1, "two", 3.14);
# Access by index (0-based)
print $nums[0]; # 1
print $nums[-1]; # 5 (last element)
# Modify an element
$nums[0] = 100;
# Range operator
my @range = (1 .. 10); # 1 to 10
# Length in scalar context
my $count = scalar @nums; # 5
my $count2 = @nums; # 5配列関数
push/pop/unshift/shift
my @stack = (1, 2, 3);
# push/pop operate on the END
push @stack, 4, 5; # (1, 2, 3, 4, 5)
my $last = pop @stack; # 5
# unshift/shift operate on the START
unshift @stack, 0; # (0, 1, 2, 3, 4)
my $first = shift @stack; # 0
# @stack is now (1, 2, 3, 4)
print "@stack\n";
# splice is the general-purpose tool
splice(@stack, 1, 0, 'x'); # insert at index 1配列スライス
@スライスはリストを返します
my @nums = (10, 20, 30, 40, 50);
# Array slice (returns a list)
my @slice = @nums[1, 3]; # (20, 40)
my @range = @nums[0 .. 2]; # (10, 20, 30)
# Modify multiple elements via slice
@nums[1, 3] = (200, 400);
# Last index
my $last_idx = $#nums; # 4
# Negative indices count from the end
print $nums[-1]; # 50
print $nums[-2]; # 400ソート
<=> 数値比較、cmp 文字列比較
my @arr = (1, 2, 3, 4, 5);
# splice ARRAY, OFFSET, LENGTH, LIST
my @removed = splice(@arr, 1, 2); # removes (2, 3)
# @arr is now (1, 4, 5)
# Insert without removing (LENGTH = 0)
splice(@arr, 1, 0, 'a', 'b'); # (1, 'a', 'b', 4, 5)
# Replace elements
splice(@arr, 0, 2, 'x'); # replace first 2 with 'x'
# Remove everything from offset to end
my @rest = splice(@arr, 2);mapとgrep
mapは変換、grepはフィルタ
my @nums = (3, 1, 4, 1, 5, 9);
# Default sort is lexicographic (string)
my @s1 = sort @nums;
# Numeric ascending
my @s2 = sort { $a <=> $b } @nums;
# Numeric descending
my @desc = sort { $b <=> $a } @nums;
# String sort
my @words = qw(banana apple Cherry);
my @alpha = sort { lc($a) cmp lc($b) } @words;
# Schwartzian transform (sort by computed key)
my @sorted = map { $_->[0] }
sort { $a->[1] <=> $b->[1] }
map { [$_, length($_)] } @words;Array length & scalar context
An array's behavior depends on context: scalar context gives length, list/string context gives elements joined by $" (default space). Use scalar() to force scalar context when needed.
my @arr = (1, 2, 3, 4, 5);
# Scalar context returns length
my $len = @arr; # 5
print "Length: $len\n";
# String context joins with $"
print "Array: @arr\n"; # 1 2 3 4 5
# Change separator
local $" = ", ";
print "@arr\n"; # 1, 2, 3, 4, 5
# Last index
print "Last index: $#arr\n"; # 4
# Force scalar context
print scalar(@arr); # 5ハッシュ
ハッシュ操作
%プレフィックスはハッシュを示します
my %ages = (Alice => 30, Bob => 25, Carol => 35);
# Fat comma => auto-quotes the left side
my %h2 = (name => 'Alice', age => 30);
# Same as list of pairs:
my %h3 = ('name', 'Alice', 'age', 30);
# Access / modify a value
print $ages{Alice}; # 30
$ages{Dave} = 40; # add
$ages{Alice} = 31; # modify
# Delete a key
delete $ages{Bob};ハッシュの反復
each/keys/values
my %h = (a => 1, b => 2, c => 3);
# Iterate keys
for my $k (keys %h) {
print "$k => $h{$k}\n";
}
# Get all values
my @vals = values %h;
# each() returns key/value pairs iteratively
while (my ($k, $v) = each %h) {
print "$k = $v\n";
}
# Sorted keys
for my $k (sort keys %h) { ... }ハッシュ関数
exists/delete/keys/values
my %h = (name => 'Alice', age => 30);
# exists checks if a key is present
if (exists $h{name}) {
print "Name exists\n";
}
# defined checks if the value is defined
if (defined $h{age}) { ... }
# delete removes a key, returns its value
my $removed = delete $h{age};
# Delete multiple keys (slice)
delete @h{qw(name age)};
# Empty a hash
%h = ();ハッシュスライス
@ハッシュスライス
my %h = (a => 1, b => 2, c => 3);
# Hash slice (returns list of values)
my @vals = @h{qw(a b)}; # (1, 2)
# Modify slice
@h{qw(a b)} = (10, 20);
# Key/value slice (v5.20+)
my @pairs = %h{qw(a b)}; # (a, 10, b, 20)
# Index/value slice
my @iv = %h{qw(a b)};
# Check multiple keys
my @present = grep { exists $h{$_} } qw(a x b);Multidimensional Hashes
Perl hashes hold scalar values, so nested structures use hash/array references. Auto-vivification automatically creates intermediate references when you assign to a deep key, which is convenient but can hide bugs.
my %people = (
alice => { age => 30, city => 'NYC' },
bob => { age => 25, city => 'LA' },
);
# Access nested values
print $people{alice}{age}; # 30
print $people{bob}{city}; # LA
# Add new nested entry
$people{carol}{age} = 35;
$people{carol}{city} = 'SF';
# Auto-vivification creates intermediate refs
$people{dave}{hobbies}[0] = 'reading';
# %people{dave} created automaticallyCommon Hash Operations
scalar keys %h gives the count. reverse %h swaps keys/values (lossy if values aren't unique). Merging with (%a, %b) flattens then rebuilds. List::Util provides min/max over the values.
my %h = (a => 1, b => 2, c => 3);
# Number of keys
my $count = scalar keys %h;
# Reverse a hash (values become keys)
my %rev = reverse %h; # (1 => a, 2 => b, 3 => c)
# Merge hashes
my %merged = (%h, d => 4);
# Check if empty
print "empty\n" if !keys %h;
# Reset each() iterator
keys %h; # resets iterator (v5.18+)
# Get min/max value
use List::Util qw(min max);
my ($min, $max) = (min(values %h), max(values %h));リファレンス
リファレンスの作成
\はリファレンスを作成、[] {}は無名リファレンスを作成
my $score = 85;
if ($score >= 90) {
print "A\n";
} elsif ($score >= 80) {
print "B\n";
} elsif ($score >= 70) {
print "C\n";
} else {
print "F\n";
}
# Statement modifier form
print "Pass\n" if $score >= 60;
# Note: it is 'elsif', NOT 'elseif'デリファレンス
->矢印デリファレンス
my $logged_in = 0;
unless ($logged_in) {
print "Please log in\n";
}
# Equivalent: if (!$logged_in) { ... }
# Statement modifier
print "Error\n" unless $ok;
# unless/else (often avoid for readability)
unless ($ok) {
print "fail\n";
} else {
print "pass\n";
}ネストした構造
隣接する添字間の矢印は省略可能
# while loop
my $i = 0;
while ($i < 5) {
print "$i\n";
$i++;
}
# until = while NOT
my $done = 0;
until ($done) {
$done = check_something();
}
# do-while style (runs at least once)
my $n = 0;
do {
print $n++;
} while ($n < 3);
# Infinite loop
while (1) { last if $done; }配列リファレンスの配列
二次元配列
# C-style for loop
for (my $i = 0; $i < 5; $i++) {
print "$i\n";
}
# foreach over a list (for and foreach are interchangeable)
foreach my $item (1, 2, 3) {
print "$item\n";
}
# Range operator
for my $n (1 .. 10) {
print "$n ";
}
# Uses default $_ variable
for (1 .. 5) {
print "$_\n";
}last/next/redo
last exits the loop (like break), next skips to the next iteration (like continue), redo restarts the current iteration without re-evaluating the condition. Labels let you control outer loops.
# last = break out of loop
for my $i (1 .. 10) {
last if $i == 5;
print "$i ";
}
# prints: 1 2 3 4
# next = skip to next iteration
for my $i (1 .. 5) {
next if $i % 2 == 0;
print "$i "; # 1 3 5
}
# redo = re-run current iteration without re-checking
my $count = 0;
while (<$fh>) {
$count++;
redo if $count < 3;
}
# Labeled loops for nested control
OUTER: for my $i (1..3) {
for my $j (1..3) {
last OUTER if $i == 2 && $j == 2;
}
}given/when (switch)
given/when provides switch/case semantics using smart matching. It's experimental, so disable the warning or prefer explicit if/elsif chains for production code. The match can compare against values, arrays, or regexes.
use feature 'switch';
no warnings 'experimental::smartmatch';
my $val = 2;
given ($val) {
when (1) { print "one\n" }
when (2) { print "two\n" }
when ([3, 4]) { print "three or four\n" }
when (/^\d+$/) { print "a number\n" }
default { print "something else\n" }
}
# given/when is experimental; many prefer if/elsif
if ($val == 1) { print "one\n" }
elsif ($val == 2) { print "two\n" }制御フロー
if-elsif-else
elsifであってelseifではない
my $str = "Hello, World";
# =~ binding operator applies a regex
if ($str =~ /World/) {
print "Matched\n";
}
# Negated match
if ($str !~ /foo/) {
print "No foo\n";
}
# Case-insensitive with /i
if ($str =~ /hello/i) {
print "Found hello\n";
}
# Implicit match against $_
for ("cat", "dog", "bat") {
print "$_\n" if /at/; # cat, bat
}unless
unlessはifの否定です
my $str = "Hello, World";
# Replace first occurrence
$str =~ s/World/Perl/; # Hello, Perl
# Replace all (g = global)
my $text = "a-b-c";
$text =~ s/-/_/g; # a_b_c
# Case-insensitive replace
$str =~ s/hello/hi/i;
# Evaluate replacement as code (e)
my $s = "2+3";
$s =~ s/(\d+)\+(\d+)/$1 + $2/e; # 5
# tr/// transliteration (character mapping)
my $dna = "ACGT";
$dna =~ tr/ACGT/TGCA/; # TGCAwhileとuntil
untilはwhileの否定です
my $str = "2024-01-15";
# Numbered capture groups
if ($str =~ /(\d{4})-(\d{2})-(\d{2})/) {
print "Year: $1\n"; # 2024
print "Month: $2\n"; # 01
print "Day: $3\n"; # 15
}
# Named captures (v5.10+)
if ($str =~ /(?<year>\d{4})-(?<month>\d{2})/) {
print $+{year}; # 2024
print $+{month}; # 01
}
# Capture all matches globally
my @nums = ($str =~ /(\d+)/g); # (2024, 01, 15)forとforeach
for/foreachは互換的に使用可能
# Quantifiers
/a/ # exactly one
/a?/ # 0 or 1
/a*/ # 0 or more
/a+/ # 1 or more
/a{3}/ # exactly 3
/a{2,4}/ # 2 to 4
/a{3,}/ # 3 or more
# Greedy vs non-greedy (lazy)
/a.*/ # greedy (matches as much as possible)
/a.*?/ # non-greedy (matches as little as possible)
# Anchors
/^start/ # beginning of string
/end$/ # end of string
/\bword\b/ # word boundary
/\A/ # absolute start of string
/\z/ # absolute end of stringlastとnext
last=break、next=continue
# Predefined classes
/\d/ # digit [0-9]
/\D/ # non-digit
/\w/ # word char [a-zA-Z0-9_]
/\W/ # non-word char
/\s/ # whitespace
/\S/ # non-whitespace
/./ # any char except newline
# Custom classes
/[aeiou]/ # any vowel
/[^0-9]/ # NOT a digit
/[a-z]/i # case-insensitive range
# POSIX classes
/[[:alpha:]]/ # letters
/[[:digit:]]/ # digits
/[[:space:]]/ # whitespace
/[[:upper:]]/ # uppercasegiven-when
switch-caseに類似(実験的)
# Common modifiers
/abc/i # case-insensitive
/abc/g # global (all matches)
/abc/m # multiline (^/$ match line boundaries)
/abc/s # single-line (. matches newline)
/abc/x # extended (whitespace and comments)
# Extended mode for readability
my $re = qr{
^\d{4} # year
-
\d{2} # month
-
\d{2} # day
}x;
# qr// pre-compiles a regex
my $pattern = qr/\bword\b/i;
if ($str =~ $pattern) { ... }サブルーチン
サブルーチンの定義
@_が引数配列です
my $s = "Hello, World";
# length
print length($s); # 12
# substr STRING, OFFSET, LENGTH, REPLACEMENT
print substr($s, 0, 5); # Hello
print substr($s, 7); # World
print substr($s, -5); # World (negative offset)
# 4-argument substr (replace in place)
my $str = "Hello, World";
substr($str, 0, 5) = "Hi"; # Hi, World
# Lvalue form modifies original
substr($s, 0, 1) = "J";引数の分割代入
my ($a, $b) = @_で引数を分割代入
my $s = "Hello, World";
# index STRING, SUBSTR, POSITION
my $pos = index($s, "World"); # 7
my $pos2 = index($s, "o"); # 4 (first)
my $pos3 = index($s, "o", 5); # 8 (from position 5)
my $not = index($s, "xyz"); # -1 (not found)
# rindex searches from the end
my $last = rindex($s, "o"); # 8
# Count occurrences of 'l'
my $count = 0;
my $p = 0;
while (($p = index($s, "l", $p)) >= 0) {
$count++;
$p++;
}可変長引数
@_にすべての引数が含まれます
my $line = "Hello\n";
# chomp removes the line terminator (safe)
chomp $line; # $line = "Hello", returns 1
# chomp a whole array at once
my @lines = ("a\n", "b\n", "c\n");
chomp @lines; # removes \n from all
# chop removes the last character (any char, risky)
my $s = "abc";
chop $s; # "ab"
# chomp returns the count removed
my $cnt = chomp(my $x = "test\n"); # $cnt = 1
# chop returns the removed character
my $c = chop my $y = "xyz"; # $c = 'z'戻り値
複数の値(リスト)を返すことができます
# split /PATTERN/, EXPR, LIMIT
my @parts = split /,/, "a,b,c"; # (a, b, c)
my @lim = split /,/, "a,b,c", 2; # (a, "b,c")
# Split on whitespace
my @words = split /\s+/, "one two three";
# Split into characters
my @chars = split //, "abc"; # (a, b, c)
# join SEPARATOR, LIST
my $csv = join(",", "a", "b", "c"); # a,b,c
my $str = join(" - ", @parts);
# Empty separator joins without delimiter
my $joined = join("", @chars); # abcサブルーチンリファレンス
無名サブルーチン
my $s = "Hello World";
print lc($s); # hello world
print uc($s); # HELLO WORLD
print lcfirst($s); # hello World
print ucfirst($s); # Hello World (already capped)
# In-string case modifiers (\L \U \u \l \E)
my $name = "Alice";
print "\L$name\E"; # alice (\L starts, \E ends)
print "\U$name\E"; # ALICE
print "\u$name"; # Alice (capitalize first char)
print "\l$name"; # alice (lowercase first char)
# Title-case each word via regex
$s =~ s/(\w+)/\u\L$1/g; # Hello Worldsprintf & printf
printf prints formatted text; sprintf returns it. Format specifiers: %s string, %d integer, %f float, %x hex, %o octal, %b binary. Width and precision control padding: %5d, %05d, %.2f.
# printf FORMAT, LIST (prints)
printf "Name: %s, Age: %d\n", "Alice", 30;
printf "Pi: %.2f\n", 3.14159; # 3.14
printf "%5d\n", 42; # ' 42' (right-aligned)
printf "%-5d|\n", 42; # '42 |' (left-aligned)
printf "%05d\n", 42; # '00042' (zero-padded)
# sprintf returns the formatted string
my $date = sprintf("%04d-%02d-%02d", 2024, 1, 15);
# "2024-01-15"
# Common specifiers: %s %d %f %x %o %b %%
printf "Hex: %x, Oct: %o, Bin: %b\n", 255, 8, 5;正規表現
基本的なマッチング
=~バインディング演算子
sub greet {
my $name = shift; # default: shifts from @_
print "Hello, $name!\n";
}
greet("Alice"); # Hello, Alice!
# Subs are global by default
sub add {
my ($a, $b) = @_; # unpack arguments
return $a + $b;
}
print add(2, 3); # 5
# Forward declaration (define later)
sub compute;
print compute(4);キャプチャ
$1 $2または$+{name}
sub sum {
my $total = 0;
$total += $_ for @_; # iterate all args
return $total;
}
print sum(1, 2, 3, 4); # 10
# Named arguments via hash
sub info {
my %args = @_;
print "Name: $args{name}\n";
print "Age: $args{age}\n";
}
info(name => "Alice", age => 30);
# Pass arrays/hashes by reference
sub total {
my $arr = shift;
my $sum = 0;
$sum += $_ for @$arr;
return $sum;
}置換
s///置換、tr///文字変換
# Single return value
sub square { return $_[0] ** 2; }
# Return a list
sub min_max {
my @nums = @_;
my ($min, $max) = ($nums[0], $nums[0]);
for (@nums) {
$min = $_ if $_ < $min;
$max = $_ if $_ > $max;
}
return ($min, $max);
}
my ($lo, $hi) = min_max(3, 1, 4, 1, 5);
# Implicit return (last expression)
sub name { "Alice" } # returns "Alice"
# Void context (no return needed)
sub log_msg { print "log: $_[0]\n"; }正規表現量指定子
正規表現量指定子
sub get_data {
if (wantarray) {
return (1, 2, 3); # list context
} elsif (defined wantarray) {
return "scalar"; # scalar context
} else {
return; # void context
}
}
my @list = get_data(); # (1, 2, 3)
my $scalar = get_data(); # "scalar"
get_data(); # void
# localtime is context-sensitive
my $t = localtime(); # scalar: "Mon Jan 1 12:00:00 2024"
my @t = localtime(); # list: (sec, min, hour, mday, ...)
# scalar() forces scalar context
print scalar(localtime());文字クラス
定義済みおよびカスタム文字クラス
# Anonymous sub (coderef)
my $greet = sub {
my $name = shift;
return "Hi, $name";
};
print $greet->("Alice"); # Hi, Alice (preferred)
print &$greet("Bob"); # older syntax
# Closure: captures outer variable
sub make_counter {
my $count = 0;
return sub { return ++$count; };
}
my $c = make_counter();
print $c->(); # 1
print $c->(); # 2 (count persists)
# Pass subs as arguments
sub apply { my ($f, $x) = @_; return $f->($x); }
print apply(sub { $_ * 2 }, 21); # 42Named Arguments & Defaults
Collect named args into a hash and apply defaults with //= (defined-or). You can mix positional and named args by putting the hash last. Returning a reference is common for option bundles.
sub create_user {
my %args = @_;
# Apply defaults with defined-or
$args{role} //= 'user';
$args{active} //= 1;
return \%args;
}
my $user = create_user(
name => 'Alice',
email => '[email protected]',
);
print $user->{role}; # user (default applied)
# Mix positional + named (named must come last)
sub point {
my ($x, $y, %opts) = @_;
print "($x, $y) color=$opts{color}\n";
}
point(1, 2, color => 'red');文字列関数
文字列操作
大文字小文字変換
# 3-argument open (recommended)
open(my $fh, '<', 'input.txt')
or die "Cannot open input.txt: $!";
# Read the whole file
my @lines = <$fh>;
close $fh;
# Modes: < read, > write (truncate), >> append,
# +< read/write, +> read/write (truncate)
open(my $out, '>', 'output.txt')
or die "Cannot write: $!";
open(my $app, '>>', 'log.txt')
or die "Cannot append: $!";部分文字列
substrは置換にも使用可能
open(my $fh, '<', 'file.txt') or die $!;
# Line by line (memory efficient)
while (my $line = <$fh>) {
chomp $line;
print "Read: $line\n";
}
# Slurp entire file (undef the record separator)
local $/;
my $content = <$fh>;
# Read all lines into an array
my @lines = <$fh>;
close $fh;
# $. holds the current line number
open(my $f2, '<', 'file.txt') or die $!;
while (<$f2>) { print "$.: $_"; }分割と結合
split/join
open(my $fh, '>', 'out.txt') or die $!;
print $fh "Hello, File!\n";
print $fh "Second line\n";
# Formatted write
printf $fh "%d: %s\n", 1, "first";
# Autoflush (no buffering)
use IO::Handle;
$fh->autoflush(1);
# Or via select
my $old = select($fh); $| = 1; select($old);
close $fh; # flushes and closes検索
index/rindex/sprintf
# <> reads from files in @ARGV, or STDIN if none
while (<>) {
print "$.: $_";
}
# Equivalent to: while (my $line = <ARGV>) { ... }
# Read all of stdin (or all arg files)
my @input = <>;
# Specify files programmatically
@ARGV = ('file1.txt', 'file2.txt');
while (<>) {
chomp;
print ">> $_\n";
}
# In-place editing
$^I = '.bak'; # backup extension
while (<>) { s/foo/bar/g; print; }chompとchop
chompは改行を削除、chopは最後の文字を削除
# Lexical filehandle (modern, recommended)
open(my $fh, '<', $file) or die $!;
# Bareword filehandle (legacy, avoid)
open(IN, '<', $file) or die $!;
my $line = <IN>;
close IN;
# Standard handles: STDIN, STDOUT, STDERR
print STDOUT "to stdout\n";
my $err = <STDIN>;
warn "to stderr\n"; # STDERR is unbuffered
# Duplicate a handle
open(my $log, '>&', STDERR) or die $!;
# Open a filehandle to a string (in-memory)
open(my $mem, '>', \my $buffer) or die $!;
print $mem "stored\n";File::Slurper
File::Slurper is the modern, efficient way to read/write whole files. It handles encodings and binmode correctly, unlike hand-rolled slurp code. Prefer it over do { local $/; <$fh> } in new code.
use File::Slurper qw(read_text write_text append_text read_lines);
# Read entire file as a string
my $text = read_text('file.txt');
# Write a string to a file
write_text('out.txt', "Hello\n");
# Append to a file
append_text('log.txt', "New entry\n");
# Read all lines (without newlines by default)
my @lines = read_lines('data.csv');
# Binary files
use File::Slurper qw(read_binary write_binary);
my $bytes = read_binary('image.png');
write_binary('copy.png', $bytes);ファイルI/O
ファイルを開く
$!はシステムエラーメッセージです
opendir(my $dh, '.') or die "Cannot open dir: $!";
while (my $entry = readdir($dh)) {
next if $entry =~ /^\./; # skip dotfiles
print "$entry\n";
}
# Or get all entries at once
rewinddir($dh);
my @entries = readdir($dh);
closedir $dh;
# Filter to only subdirectories
opendir(my $d, '.') or die $!;
my @dirs = grep { -d $_ } readdir($d);
closedir $d;ファイルへの書き込み
>上書き、>>追記
# glob expands filename wildcards
my @files = glob('*.txt');
my @perl = glob('*.pl *.pm');
# Angle-bracket form (legacy)
my @same = <*.txt>;
# With a path
my @logs = glob('/var/log/*.log');
# Recursive globbing
use File::Glob qw(:bsd_glob);
my @all = bsd_glob('**/*.pm'); # needs :bsd_glob
# Capture flags: GLOB_ERR, GLOB_MARK (trailing / on dirs)
my @marked = bsd_glob('*', GLOB_MARK);ダイヤモンド演算子
<>ダイヤモンド演算子
# Create a directory (default perms modified by umask)
mkdir 'newdir' or die $!;
mkdir 'newdir', 0755; # explicit permissions
# Create nested directories
use File::Path qw(make_path remove_tree);
make_path('a/b/c');
make_path('x/y', { mode => 0755 });
# Remove a directory (must be empty)
rmdir 'emptydir' or die $!;
# Remove recursively
remove_tree('a');
# Change working directory
chdir '/tmp' or die $!;
# Get current directory
use Cwd qw(getcwd);
print getcwd();ファイルテスト
ファイルテスト演算子
use File::Find;
my @found;
find(sub {
return if -d; # skip directories
push @found, $File::Find::name
if /\.pm\z/;
}, '.');
# finddepth visits directories after their contents
finddepth(sub {
unlink $_ if -f and -M $_ > 30; # delete old files
}, '/tmp/old');
# Multiple starting directories
find(\&wanted, qw(src lib t));
sub wanted {
my $path = $File::Find::name;
print "$path\n" if -f $path;
}File::Slurper
モダンなファイル読み書きモジュール
use Path::Tiny;
# Create a path object
my $path = path('/tmp/test.txt');
# File operations
$path->touch;
$path->spew("content\n");
my $content = $path->slurp;
my @lines = $path->lines;
# Path manipulations
my $parent = $path->parent;
my $child = $path->child('sub.txt');
my $abs = $path->absolute;
my $rel = $abs->relative('/tmp');
# Iterate directory contents
for my $f (path('.')->children) {
print $f, "\n" if $f->is_file;
}File::Copy & unlink
File::Copy provides copy and move across filesystems. File::Spec builds portable paths without hardcoding separators. unlink deletes files (returns the count removed); it cannot delete directories.
use File::Copy qw(copy move);
# Copy a file
copy('src.txt', 'dst.txt') or die $!;
copy('src.txt', 'dst.txt', 8192); # buffer size
# Move / rename
move('old.txt', 'new.txt') or die $!;
# Portable paths via File::Spec
use File::Spec;
my $path = File::Spec->catfile('dir', 'file.txt');
my ($vol, $dir, $file) = File::Spec->splitpath($path);
# Delete files
unlink qw(a.txt b.txt c.txt);
my $removed = unlink grep { -f } glob('*.tmp');ディレクトリ
ディレクトリを開く
readdirはディレクトリエントリを読み取ります
my $scalar = 42;
my @arr = (1, 2, 3);
my %h = (a => 1);
# Backslash creates a reference
my $sref = \$scalar;
my $aref = \@arr;
my $href = \%h;
my $cref = \&some_sub;
# Check what a reference points to
print ref($aref); # ARRAY
print ref($href); # HASH
print ref($sref); # SCALAR
print ref($cref); # CODE
# A non-reference returns ''
print ref("hi"); # (empty string)glob
globファイル名ワイルドカード
my $aref = [1, 2, 3];
my $href = { a => 1, b => 2 };
# Whole array
my @arr = @$aref; # or @{ $aref }
my $len = scalar @$aref;
# Single element via arrow
print $aref->[0]; # 1
print $#$aref; # last index (2)
# Whole hash
my %h = %$href;
my @keys = keys %$href;
# Single value via arrow
print $href->{a}; # 1
# Block form for clarity
my @arr2 = @{ $aref };ディレクトリ操作
ディレクトリとファイルの操作
# Anonymous array reference: [ ]
my $arr = [1, 2, 3];
print $arr->[0]; # 1
# Anonymous hash reference: { }
my $h = { name => 'Alice', age => 30 };
print $h->{name};
# Nested anonymous structures
my $data = {
users => [ { name => 'a' }, { name => 'b' } ],
count => 2,
};
# Anonymous subroutine
my $code = sub { print "hi\n" };File::Find
ディレクトリツリーを再帰的に走査
# Array of arrays (2D)
my $matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
print $matrix->[1][2]; # 6 (second arrow optional)
# Hash of hashes
my $config = {
db => { host => 'localhost', port => 3306 },
app => { name => 'MyApp', debug => 1 },
};
print $config->{db}{host}; # localhost
# Auto-vivification creates intermediate refs
my %tree;
$tree{a}{b}{c} = 1; # builds the path automaticallyArrow Operator
The arrow -> dereferences: $ref->[idx] for arrays, $ref->{key} for hashes, $ref->() for code, $obj->method for objects. Between consecutive subscripts the arrow is optional for readability.
my $arr = [[1, 2], [3, 4]];
my $h = { users => [{ name => 'a' }] };
# Arrow between subscripts (second is optional)
print $arr->[0][1]; # 2
print $h->{users}[0]{name}; # a
# Arrow for coderef calls
my $greet = sub { "hi $_[0]" };
print $greet->("Bob"); # hi Bob
# Method calls on objects
$obj->method($arg);
# Slicing a dereferenced array
my @vals = @{ $h->{users} };Reference Types
ref() returns the class name for blessed references (objects), which can hide the underlying type. Scalar::Util::reftype() always returns the true structural type. Use weaken() to break reference cycles.
use Scalar::Util qw(reftype weaken);
my $aref = [];
my $href = {};
my $cref = sub {};
print ref($aref); # ARRAY
print reftype($aref); # ARRAY
# A blessed reference (object)
my $obj = bless {}, 'MyClass';
print ref($obj); # MyClass
print reftype($obj); # HASH (the underlying type)
# Type checks
if (ref($r) eq 'ARRAY') { ... }
if (ref($r) eq 'HASH') { ... }
# weaken avoids circular-reference memory leaks
weaken($r);フォーマット
フォーマットの定義
formatが出力フォーマットを定義
# use: runs at compile time, calls the module's import()
use strict;
use warnings;
use Data::Dumper;
# require: runs at runtime, does NOT call import()
require MyModule;
# Conditional loading (runtime)
if ($DEBUG) {
require Carp;
Carp->import('confess');
}
# use with version and import list
use v5.36;
use List::Util 1.33 qw(first sum max);
# use MODULE VERSION LIST
use Data::Dumper qw(Dumper);フォーマット指定子
フォーマットフィールド指定子
# Add directories to the module search path
use lib '/home/me/lib';
use lib 'lib', 'local/lib';
# Locate a path relative to the script
use FindBin;
use lib "$FindBin::Bin/lib";
# Inspect the search path
print join("\n", @INC);
# Add at runtime (then require)
push @INC, '/path/to/lib';
require MyModule;
# Remove an entry
@INC = grep { !/local/ } @INC;Exporter
Exporter controls what a module exposes. @EXPORT forces exports (often discouraged); @EXPORT_OK lets callers opt in (preferred). %EXPORT_TAGS groups exports for convenient import like ':all'.
package MyModule;
use parent 'Exporter';
our @EXPORT = qw(func1); # exported by default
our @EXPORT_OK = qw(func2 func3); # exported on request
our %EXPORT_TAGS = (
all => [qw(func1 func2 func3)],
);
sub func1 { return "one"; }
sub func2 { return "two"; }
sub func3 { return "three"; }
1; # a module must return a true value
# Usage in another file:
# use MyModule; # gets func1
# use MyModule qw(func2); # gets func2 only
# use MyModule ':all'; # gets all threeBEGIN & END
BEGIN blocks run at compile time (useful for setup that must happen before the rest compiles). END blocks run at program exit (for cleanup). CHECK and INIT run between compile and run time.
# BEGIN runs at compile time
BEGIN {
print "Compiled\n";
require MyModule;
}
# END runs at exit (in LIFO order)
END {
print "Cleaning up\n";
}
# Other phases: UNITCHECK, CHECK, INIT
INIT { print "Running\n"; }
# Compile-time constant definition
use constant DEBUG => 1;
# BEGIN to push a custom lib path early
BEGIN { push @INC, '/custom' }package
package declares a namespace. A module file (MyModule.pm) usually contains one package matching its name. The file must end with a true value (1;) so 'use' knows it loaded successfully.
package MyModule;
use strict;
use warnings;
our $VERSION = '1.00';
sub new {
my $class = shift;
return bless {}, $class;
}
sub method {
my $self = shift;
return "called";
}
1; # required: modules must return a true value
# Switch back to the main package
package main;
my $obj = MyModule->new;
print $obj->method;Constants
use constant creates inlinable constants (no sigil). Readonly and Const::Fast offer lexically-scoped immutable scalars/arrays/hashes. Constants are really subs with a () prototype, allowing them to be inlined.
# use constant (compile-time)
use constant {
PI => 3.14159,
MAX => 100,
DEBUG => 0,
};
print PI; # 3.14159
# Readonly (lexically scoped, immutable)
use Readonly;
Readonly my $NAME => 'Alice';
# Const::Fast
use Const::Fast;
const my $count => 5;
# A constant is just a sub with an empty prototype
sub MAX_CONNECTIONS () { 10 }
print MAX_CONNECTIONS; # 10パッケージ
パッケージの定義
packageは名前空間を宣言します
package Animal;
use strict;
use warnings;
sub new {
my ($class, %args) = @_;
my $self = { name => $args{name}, sound => 'generic' };
return bless $self, $class;
}
sub name { shift->{name} }
1;
# bless associates a reference with a package (the class).
# $self is a hash ref blessed into Animal.パッケージの使用
useは読み込みとインポートを行います
package Point;
use strict;
use warnings;
sub new {
my ($class, $x, $y) = @_;
my $self = { x => $x, y => $y };
return bless $self, $class;
}
# Usage (arrow syntax preferred)
my $p = Point->new(3, 4);
# Indirect syntax ( discouraged)
my $p2 = new Point(3, 4);
# Named-argument constructor
sub new_named {
my ($class, %args) = @_;
return bless \%args, $class;
}Exporter
Exporterはエクスポートを制御します
package Point;
sub new { ... }
# Instance method: first arg is the object
sub distance {
my ($self, $other) = @_;
my $dx = $self->{x} - $other->{x};
my $dy = $self->{y} - $other->{y};
return sqrt($dx**2 + $dy**2);
}
# Getter
sub x { my $self = shift; return $self->{x}; }
# Setter (chainable)
sub set_x {
my ($self, $x) = @_;
$self->{x} = $x;
return $self;
}
# Class method
sub count { our $count; return ++$count }Inheritance (use parent)
use parent sets @ISA cleanly and calls the parent's import. Use SUPER::method to call an overridden parent method. Multiple inheritance is supported but method resolution order (MRO) can be subtle; use mro::get_linear_isa to inspect.
package Dog;
use parent 'Animal';
sub new {
my ($class, %args) = @_;
my $self = $class->SUPER::new(%args); # call parent
$self->{breed} = $args{breed};
return $self;
}
sub speak {
my $self = shift;
return "Woof!";
}
# Direct @ISA (lower-level)
package Cat;
our @ISA = ('Animal');
# Multiple inheritance
package Duck;
use parent qw(Flyable Animal);Accessors
You can write accessors by hand (one sub handles both get and set). Modules like Class::Accessor, Class::Tiny, Moo, or Moose generate them, reducing boilerplate. The choice depends on your dependency budget.
# Hand-written accessor (getter + setter)
sub name {
my $self = shift;
if (@_) { $self->{name} = shift; return $self; }
return $self->{name};
}
# Class::Accessor generates them
package User;
use parent 'Class::Accessor';
__PACKAGE__->mk_accessors(qw(name email age));
# Usage
my $u = User->new({ name => 'Alice' });
$u->name; # get
$u->name('Bob'); # set
# Moo / Moose generate accessors declaratively
has name => (is => 'rw');DESTROY & AUTOLOAD
DESTROY is called automatically when an object's refcount hits zero (use for cleanup like closing handles). AUTOLOAD intercepts calls to undefined methods, enabling dynamic accessors or delegation, but use it sparingly.
package FileHandle::Custom;
sub new {
my ($class, $file) = @_;
open(my $fh, '<', $file) or die $!;
return bless { fh => $fh }, $class;
}
sub DESTROY {
my $self = shift;
close $self->{fh} if $self->{fh};
# auto-called when refcount reaches 0
}
# AUTOLOAD catches undefined method calls
sub AUTOLOAD {
my $self = shift;
our $AUTOLOAD;
my $method = $AUTOLOAD;
$method =~ s/.*:://;
return $self->{$method}; # treat as accessor
}モジュール
モジュールの読み込み
useとrequireの違い
my $f = 'file.txt';
print "exists\n" if -e $f; # exists
print "regular\n" if -f $f; # plain file
print "dir\n" if -d $f; # directory
print "symlink\n" if -l $f; # symbolic link
print "socket\n" if -S $f; # socket
print "pipe\n" if -p $f; # named pipe (FIFO)
print "char dev\n" if -c $f; # character device
print "block dev\n" if -b $f; # block device
# Stack tests (uses the same stat cache)
print "regular file\n" if -f -e $f;
# _ reuses the last stat result
print "size: ", -s _ if -e $f;モジュールパス
use libで検索パスを追加
my $f = 'script.pl';
print "readable\n" if -r $f; # effective uid can read
print "writable\n" if -w $f; # effective uid can write
print "executable\n" if -x $f; # effective uid can exec
print "owned\n" if -o $f; # owned by effective uid
# Real uid variants (rarely needed)
print "real read\n" if -R $f;
print "real write\n" if -W $f;
print "real exec\n" if -X $f;
# setuid / setgid / sticky
print "setuid\n" if -u $f;
print "setgid\n" if -g $f;
print "sticky\n" if -k $f;CPANモジュール
cpanmはCPANモジュールをインストール
my $f = 'data.bin';
# -s returns size in bytes (or undef if missing)
my $size = -s $f;
print "Size: $size bytes\n";
# Empty file
if (-z $f) { print "empty\n"; }
# Non-empty (size > 0)
if (-s $f) { print "has data\n"; }
# Human-readable size
use Number::Bytes::Human qw(format_bytes);
print format_bytes(-s $f), "\n";
# stat() for full detail
my @st = stat($f);
print "Size: $st[7] bytes\n"; # index 7 is sizeTime (-M/-A/-C)
-M, -A, -C return the file's age in days relative to $^T (the script's start time), so values are positive for older files. For epoch seconds, use stat() indices 9 (mtime), 8 (atime), 10 (ctime).
my $f = 'file.txt';
# All return age in days since script start ($^T)
print -M $f; # modification age (days)
print -A $f; # access age (days)
print -C $f; # inode-change age (days)
# Older than 30 days?
if (-M $f > 30) { print "old file\n"; }
# Modified today?
if (-M $f < 1) { print "modified today\n"; }
# Epoch seconds via stat
my @st = stat($f);
my $mtime = $st[9]; # mtime (epoch)
my $atime = $st[8]; # atime (epoch)
my $ctime = $st[10]; # ctime (epoch)Text/Binary (-T/-B)
-T/-B guess text vs binary heuristically by examining the first bytes (null bytes, control chars). Empty files count as text. For real MIME types use a module like File::MimeInfo::Magic.
my $f = 'file.txt';
# -T text file, -B binary file
if (-T $f) { print "text\n"; }
if (-B $f) { print "binary\n"; }
# Perl heuristically decides from the first block
# Filter a directory to text files only
opendir(my $dh, '.');
my @text_files = grep { -f && -T } readdir($dh);
closedir $dh;
# Note: empty files count as text
# Proper MIME detection
use File::MimeInfo::Magic;
print mimetype($f);stat & lstat
stat() returns 13 fields; the most used are size (7), mode (2), mtime (9). lstat() is like stat but doesn't follow symlinks (so you can inspect the link itself). The _ operator reuses the cached result for chained tests.
my $f = 'file.txt';
# stat returns a 13-element list
my @s = stat($f);
# 0 dev, 1 ino, 2 mode, 3 nlink, 4 uid, 5 gid,
# 6 rdev, 7 size, 8 atime, 9 mtime, 10 ctime,
# 11 blksize, 12 blocks
my $size = $s[7];
my $perms = sprintf "%04o", $s[2] & 07777;
# lstat does NOT follow symlinks
my @ls = lstat($f);
# stat on an open filehandle
my @sf = stat($fh);
# _ reuses the last stat result (no new syscall)
print -s _ if -e $f;オブジェクト指向
伝統的なOOP
blessはリファレンスとパッケージを関連付けます
# Install a module from the command line:
# cpanm DBI
# cpanm Mojolicious
# cpanm --interactive Module::Name
# Install a specific version range
# cpanm DBI~">=1.6"
# Install from a git repository
# cpanm https://github.com/user/Mod.git
# Install dependencies from a cpanfile
# cpanm --installdeps .
# Install into a local directory
# cpanm -l extlib DBI
# Verbose output
# cpanm -v DBIメソッド呼び出し
->メソッド呼び出し構文
# cpanfile declares runtime and test dependencies
requires 'perl', '5.014';
requires 'DBI' => '1.6';
requires 'Mojolicious' => '9.0';
# Phase-specific dependencies
on develop => sub {
requires 'Test::Pod';
requires 'Test::Perl::Critic';
};
on test => sub {
requires 'Test::More' => '0.98';
requires 'Test::Exception';
};
recommends 'JSON::XS';
conflicts 'Old::Module';継承
use parentで継承を宣言
# Carton manages a locked dependency tree
# Install Carton: cpanm Carton
# Commands (shell):
# carton install # install from cpanfile
# carton install DBI # add a module
# carton exec ./app.pl # run with local deps
# carton bundle # vendor tarballs
# carton show # list installed
# cpanfile.snapshot locks exact versions
# local/ holds the installed modules
# In your code, ensure the lib path:
use lib 'local/lib/perl5';
use DBI;アクセサ
ゲッター/セッターを手動実装
# Install into a local directory
# cpanm -l extlib DBI
# Then use it in your script:
use lib 'extlib/lib/perl5';
use DBI;
# Bootstrap local::lib
# cpanm --local-lib=~/perl5 local::lib
use local::lib '~/perl5';
# Find a module's installed path
use Module::Util qw(module_path);
my $path = module_path('DBI');
# Check an installed version from the CLI:
# perl -MDBI -e 'print $DBI::VERSION'perlbrew
perlbrew lets you install and switch between multiple Perl versions in your home directory without touching the system Perl. 'perlbrew use' sets the perl for the current shell; 'switch' sets the default.