Change a File's Group Safely with chgrp

You have a file the wrong team can read, or a shared directory that needs a different group, and chgrp fixes it in one line. This guide uses GNU chgrp from coreutils 9.4, takes about ten minutes, and shows you where recursion and symbolic links can bite.

1. Check the command and your groups

Confirm which executable will run and which groups your account belongs to:

$ command -v chgrp
/usr/bin/chgrp
$ chgrp --version
chgrp (GNU coreutils) 9.4
$ id -Gn
alice users

The version line helps when you compare a script with another host. The manual page installed here is dated August 2026 and describes GNU coreutils 9.4. Group names are host-specific, so replace GROUP_NAME below with a group printed by your own id -Gn, or one your administrator has explicitly granted you.

Checkpoint: you have chosen one test file and one permitted group before running anything that changes ownership.

2. Change one file

The new group goes first and one or more paths follow:

$ chgrp GROUP_NAME /path/to/report.txt

Success is silent. The command changes the group owner, not the file's content or permission bits. In a script, check the exit status as well:

$ printf 'exit status: %s\n' "$?"
exit status: 0
$ stat -c 'group=%G path=%n' /path/to/report.txt
group=GROUP_NAME path=/path/to/report.txt

Check $? straight after chgrp, before the stat, because any intervening command replaces the status.

Tip: if the file belongs to another account, or local policy blocks the change, sudo chgrp ... may be right, but only if you administer that system. Elevation is not a substitute for checking the target path.

3. Show what changed across several files

Use --verbose when you want a line for every path:

$ chgrp --verbose GROUP_NAME /path/to/report.txt /path/to/archive.txt
group of '/path/to/report.txt' changed to GROUP_NAME
group of '/path/to/archive.txt' retained as GROUP_NAME

The exact wording includes your paths and varies with the old group. If you only want output when something changed, use --changes instead:

$ chgrp --changes GROUP_NAME /path/to/report.txt

Both forms leave the files in their new state.

Recovery: to undo a change, run chgrp again with the previous group, which you record beforehand with stat -c '%G' FILE. If you do not know the previous group, stop and recover it from backup or audit data rather than guessing.

4. Copy a group from a reference file

When one file already has the right group, point --reference at it:

$ stat -c 'reference group=%G path=%n' /path/to/good-file
reference group=GROUP_NAME path=/path/to/good-file
$ chgrp --reference=/path/to/good-file /path/to/report.txt
$ stat -c 'group=%G path=%n' /path/to/report.txt
group=GROUP_NAME path=/path/to/report.txt

5. Change a directory tree deliberately

Adding --recursive applies the change to the directory and everything below it:

$ chgrp --recursive --verbose GROUP_NAME /path/to/project-data

Warning: this is a broad ownership change. Inspect the path first, and consider a review with find /path/to/project-data -xdev -print if crossing mounted filesystems would be a problem. chgrp has no dry-run option, so a verbose run is not a preview.

By default, recursion does not follow symbolic links. On root protection, --preserve-root prevents recursive operation on /, while --no-preserve-root is the default and adds no such protection. Add --preserve-root to make an accidental root target fail:

$ sudo chgrp --recursive --preserve-root GROUP_NAME /path/to/project-data

Do not use --no-preserve-root in a routine command. The option name is a warning in itself.

Recovery: if recursion changes the wrong tree, stop immediately, record the affected paths from your logs or backup, and restore the intended group explicitly. There is no universal undo command because the original group may differ for every path.

6. Handle symbolic links on purpose

Without recursion, the default is --dereference: the command affects the file the link points to. With --no-dereference, it tries to change the link itself:

$ chgrp --no-dereference GROUP_NAME /path/to/link
$ stat -c 'group=%G type=%F path=%n' /path/to/link

Changing a link's own group only works on systems that support it, and elsewhere the command can fail. For recursive work, the traversal options --H, --L and --P control how links to directories are treated:

7. Diagnose a failed change

Use --verbose to identify the path that failed, then inspect it without changing anything:

$ chgrp --verbose GROUP_NAME /path/to/report.txt
chgrp: changing group of '/path/to/report.txt': Operation not permitted
$ ls -ld /path/to/report.txt
$ namei -l /path/to/report.txt

The usual causes:

Tip: --silent and --quiet suppress most errors, so avoid them while investigating.

Done means