--- name: chmod signature: 'chmod MODE, LIST' since: 5.0 status: documented categories: ["Filehandles, files, directories"] --- ```{index} single: chmod; Perl built-in ``` *[Filehandles, files, directories](../perlfunc-by-category)* # chmod Change the permission bits of a list of files. `chmod` sets each file in `LIST` to the permission `MODE`. `MODE` is a **numeric** value — the low twelve bits are the usual Unix permission triad plus the setuid, setgid, and sticky bits, exactly as accepted by `chmod(2)`. Both plain pathnames and open filehandles are accepted in `LIST`. Returns the number of files for which the underlying system call succeeded. ## Synopsis ```perl chmod MODE, LIST ``` ## What you get back The number of files successfully changed, as an integer. Zero means every call failed; a value less than `scalar @files` means a partial failure. `chmod` does **not** throw on a per-file failure — it keeps going and tallies the successes. [`$!`](../perlvar) reflects the error from the **last** failing file only. On a mixed success/failure run there is no built-in way to learn which files failed; if you need per-file error reporting, call `chmod` once per file and check the return value each time: ```perl for my $f (@files) { chmod 0644, $f or warn "chmod $f: $!"; } ``` ## Writing MODE correctly `MODE` is an integer. The three ways to spell it: - **Octal literal with leading zero**: `0644`, `0755`, `0600`. This is the conventional form and matches the digits you would type into `chmod(1)`. - **Octal literal with `0o` prefix**: `0o644`, `0o755`. Accepted since Perl 5.34; equivalent to the leading-zero form and easier to read as "octal" at a glance. - **Symbolic constants from `Fcntl`**: `use Fcntl qw(:mode); S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH` evaluates to `0755`. Useful when a permission set is built up from pieces. A string argument is almost always a bug: ```perl chmod "0644", "foo"; # WRONG — stringifies as decimal 644 (octal 1204), # grants mode --w----r-T chmod 644, "foo"; # WRONG — decimal 644 is octal 1204, same result chmod 0644, "foo"; # right chmod 0o644, "foo"; # right (Perl 5.34+) ``` If the mode genuinely arrives as a string (configuration file, CLI argument), convert it with [`oct`](oct) first: ```perl my $mode = "0644"; # string from config chmod oct($mode), "foo"; # oct("0644") == 0644 ``` ## Global state it touches Sets [`$!`](../perlvar) on any failure to match the last failing `chmod(2)` / `fchmod(2)` call. Reads no interpreter globals. ## Examples Change one file, check for success: ```perl chmod 0755, "install.sh" or die "chmod install.sh: $!"; ``` Change many files in a single call, capture the count: ```perl my $cnt = chmod 0644, "a.txt", "b.txt", "c.txt"; print "updated $cnt of 3 files\n"; ``` With an array of pathnames: ```perl my @executables = glob "bin/*"; chmod 0755, @executables; ``` Preserve existing bits, add owner write. Reads the mode with [`stat`](stat), masks to the permission bits, ORs in the new bit, and writes it back: ```perl open my $fh, "<", "foo" or die $!; my $perm = (stat $fh)[2] & 07777; chmod $perm | 0200, $fh; ``` Symbolic form via `Fcntl`: ```perl use Fcntl qw(:mode); chmod S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH, @executables; # identical to: chmod 0755, @executables; ``` Per-file error reporting (needed to learn *which* file failed on a multi-file call): ```perl my @failed; for my $f (@files) { push @failed, $f unless chmod 0644, $f; } warn "chmod failed on: @failed\n" if @failed; ``` ## Edge cases - **Empty list**: `chmod 0644` returns `0`. The mode is evaluated but no system call is made. - **String modes**: `chmod "0644", $f` and `chmod "+x", $f` are both wrong. `chmod` never parses symbolic mode strings — unlike `chmod(1)`, the built-in takes a number, not a specification. - **Filehandles vs barewords**: a bareword in `LIST` is a filename, not a filehandle. Pass a filehandle as a glob or glob reference: ```perl chmod 0644, *FH; # filehandle chmod 0644, \*FH; # filehandle chmod 0644, $fh; # filehandle (lexical) chmod 0644, "FH"; # filename "FH" — almost certainly a bug ``` On systems without `fchmod(2)`, passing a filehandle raises an exception. Linux supports `fchmod(2)`, so on the platforms pperl targets this always works. - **Setuid / setgid / sticky bits**: the high three bits of the mode word (`04000`, `02000`, `01000`) set setuid, setgid, and the sticky bit respectively. `0o4755` makes a setuid executable; `0o2775` a setgid directory. - **Symlinks**: `chmod` follows symlinks. Changing permissions on the symlink itself is not portable and is not exposed by this built-in — use `lchmod` from a module if the platform supports it. - **Permission to change permission**: only the file's owner (and root) may call `chmod(2)` on a file. Failure sets [`$!`](../perlvar) to `EPERM`. - **Non-existent paths**: `chmod` on a missing path sets [`$!`](../perlvar) to `ENOENT` and contributes `0` to the success count. It does not warn and does not die. - **umask does not apply**: [`umask`](umask) masks the mode of *newly created* files from [`open`](open), [`sysopen`](sysopen), [`mkdir`](mkdir), and similar. `chmod` sets the mode literally — no masking. ## Differences from upstream Fully compatible with upstream Perl 5.42. ## See also - [`chown`](chown) — the sibling call for changing owner/group; same list-and-return-count shape - [`stat`](stat) — read the current mode so you can modify it rather than replace it wholesale - [`umask`](umask) — default permission mask applied to *new* files; unrelated to `chmod`, which sets bits literally - [`open`](open) / [`sysopen`](sysopen) — create files; the mode argument to [`sysopen`](sysopen) is masked by [`umask`](umask) at creation time and can then be tightened or relaxed with `chmod` - [`oct`](oct) — parse `"0644"` into the integer `0644` when the mode arrives as a string - [`$!`](../perlvar) — system error from the last failing file; only meaningful for single-file calls or immediately after a failing per-file call in a loop