chgrp Command

Change Group Ownership of Files and Directories

chgrp [OPTION]... GROUP FILE...
chgrp [OPTION]... --reference=RFILE FILE...

Overview

The chgrp (change group) command changes the group ownership of files and directories in Linux and Unix systems. Every file and directory has both an owner (user) and a group associated with it. The chgrp command specifically modifies the group ownership while leaving the user ownership unchanged.

Group ownership is a crucial part of Linux's permission system, enabling multiple users who are members of the same group to share access to files and directories. This is particularly important in multi-user environments, development teams, and server administration where controlled sharing of resources is necessary.

Key Characteristics

Property Description
Purpose Change group ownership of files and directories
Permissions Required File owner or root (with some restrictions)
Recursive Option Yes (-R), applies to directories and their contents
Symlink Handling Doesn't follow symlinks by default, options available
Permission Requirements: Regular users can only change the group of files they own, and only to groups they are members of. Root can change any file's group to any group. To check which groups you belong to, use the groups command.

Understanding Linux Group Ownership

How Group Ownership Works

When you list files with ls -l, you see ownership displayed as:

-rw-r--r-- 1 craig developers 1024 Nov 24 08:30 myfile.txt
^user ^group

The group field determines which group's permissions apply to the file. Group permissions are the middle set of three in the permission string:

-rw-r--r--
^^^ user permissions (owner)
^^^ group permissions
^^^ other permissions

Common Groups on Linux Systems

Group Purpose Typical Usage
wheel System administrators (RHEL/CentOS) Members can use sudo
sudo System administrators (Debian/Ubuntu) Members can use sudo
www-data Web server processes Web content ownership
apache/httpd Apache web server Web content ownership (RHEL)
docker Docker users Access to Docker daemon
adm System monitoring Read access to log files

Detailed Examples

Example 1: Basic Group Change

$ ls -l report.txt
-rw-r--r-- 1 craig users 2048 Nov 24 08:30 report.txt

$ chgrp developers report.txt

$ ls -l report.txt
-rw-r--r-- 1 craig developers 2048 Nov 24 08:30 report.txt

# Verify you're in the developers group
$ groups
craig wheel developers docker

# Can also use GID instead of group name
$ getent group developers
developers:x:1001:craig,john,jane

$ chgrp 1001 report.txt
$ ls -l report.txt
-rw-r--r-- 1 craig developers 2048 Nov 24 08:30 report.txt
Explanation: The most basic use of chgrp changes a file's group ownership from one group to another. You must be a member of the target group (developers in this case) to perform this operation as a regular user. The file's user ownership (craig) and permissions (-rw-r--r--) remain unchanged. You can specify the group either by name or by its numeric Group ID (GID). Use getent group groupname to see a group's GID and members.
Tip: Using group names is more readable and portable across systems. Group IDs may differ between systems even if the group names are the same.

Example 2: Recursive Group Change for Directories

$ ls -la project/
total 24
drwxr-xr-x 3 craig users 4096 Nov 24 08:30 .
drwxr-xr-x 5 craig users 4096 Nov 24 08:29 ..
-rw-r--r-- 1 craig users 1234 Nov 24 08:30 README.md
drwxr-xr-x 2 craig users 4096 Nov 24 08:30 src
-rw-r--r-- 1 craig users 567 Nov 24 08:30 config.yaml

$ chgrp -R developers project/

$ ls -la project/
total 24
drwxr-xr-x 3 craig developers 4096 Nov 24 08:30 .
drwxr-xr-x 5 craig users 4096 Nov 24 08:29 ..
-rw-r--r-- 1 craig developers 1234 Nov 24 08:30 README.md
drwxr-xr-x 2 craig developers 4096 Nov 24 08:30 src
-rw-r--r-- 1 craig developers 567 Nov 24 08:30 config.yaml

$ ls -la project/src/
-rw-r--r-- 1 craig developers 890 Nov 24 08:30 main.py
-rw-r--r-- 1 craig developers 456 Nov 24 08:30 utils.py
Explanation: The -R (recursive) option changes the group ownership of a directory and all its contents, including subdirectories and their files. This is essential when you want to share an entire project directory tree with a team. Notice that after the recursive change, all files and subdirectories under project/ now belong to the developers group. This is particularly useful when setting up shared project directories for development teams.
Warning: Be careful with recursive operations on large directory trees. Always verify your command before running it, especially when run as root. A typo could affect thousands of files.

Example 3: Using --reference to Match Another File's Group

$ ls -l template.txt newfile.txt
-rw-r--r-- 1 craig developers 1024 Nov 24 08:30 template.txt
-rw-r--r-- 1 craig users 2048 Nov 24 08:31 newfile.txt

# Make newfile.txt have the same group as template.txt
$ chgrp --reference=template.txt newfile.txt

$ ls -l template.txt newfile.txt
-rw-r--r-- 1 craig developers 1024 Nov 24 08:30 template.txt
-rw-r--r-- 1 craig developers 2048 Nov 24 08:31 newfile.txt

# Useful for multiple files
$ touch file1.txt file2.txt file3.txt
$ chgrp --reference=template.txt file*.txt
$ ls -l file*.txt
-rw-r--r-- 1 craig developers 0 Nov 24 08:32 file1.txt
-rw-r--r-- 1 craig developers 0 Nov 24 08:32 file2.txt
-rw-r--r-- 1 craig developers 0 Nov 24 08:32 file3.txt
Explanation: The --reference option is extremely useful when you want to match the group ownership of one or more files to that of a reference file. Instead of having to look up or remember what group a file belongs to, you simply point to a file with the desired ownership. This is particularly handy in scripts or when you want to ensure consistent group ownership across related files. You can use this with multiple target files by using wildcards or listing multiple files.
Use Case: This is particularly useful when you're creating new files that should match the group of existing files in a shared directory, or when standardizing ownership across a set of related configuration files.

Example 4: Verbose Output for Confirmation

$ chgrp -v developers report1.txt report2.txt report3.txt
changed group of 'report1.txt' from users to developers
changed group of 'report2.txt' from users to developers
changed group of 'report3.txt' from users to developers

# Combined with recursive
$ chgrp -Rv www-data /var/www/html/
changed group of '/var/www/html/index.html' from root to www-data
changed group of '/var/www/html/css/style.css' from root to www-data
changed group of '/var/www/html/js/script.js' from root to www-data
changed group of '/var/www/html/images/logo.png' from root to www-data
...

# See only changes (not files already with correct group)
$ chgrp -cv developers *.txt
changed group of 'report1.txt' from users to developers
group of 'report2.txt' retained as developers
changed group of 'report3.txt' from users to developers
Explanation: The -v (verbose) option makes chgrp report each file it processes, showing what group change occurred. This is valuable for confirmation, logging, and troubleshooting. The -c (changes) option is similar but only reports when changes are actually made, not when the file already had the correct group. Verbose output is especially useful when performing operations on many files or when you want to create an audit trail of ownership changes. Combine with -R for detailed output during recursive operations.
Best Practice: Always use -v or -c when making important system changes or when running as root. The confirmation output can be saved to a log file for audit purposes: chgrp -Rv www-data /var/www/html/ 2>&1 | tee chgrp.log

Example 5: Handling Symbolic Links

$ ls -l mylink
lrwxrwxrwx 1 craig users 10 Nov 24 08:30 mylink -> target.txt

$ ls -l target.txt
-rw-r--r-- 1 craig users 1024 Nov 24 08:30 target.txt

# Default behavior: changes the symlink itself (usually not what you want)
$ chgrp -h developers mylink
$ ls -l mylink
lrwxrwxrwx 1 craig developers 10 Nov 24 08:30 mylink -> target.txt
$ ls -l target.txt
-rw-r--r-- 1 craig users 1024 Nov 24 08:30 target.txt

# Change the target, not the symlink (typical usage)
$ chgrp developers mylink
$ ls -l target.txt
-rw-r--r-- 1 craig developers 1024 Nov 24 08:30 target.txt

# For recursive operations, control symlink traversal
$ chgrp -R developers project/ # Doesn't follow symlinks
$ chgrp -R -L developers project/ # Follows all symlinks
$ chgrp -R -H developers project/ # Follows symlinks on command line only
Explanation: Symbolic links require special consideration. By default, when you run chgrp on a symlink without the -h option, it changes the group of the target file, not the symlink itself. The -h (no-dereference) option changes the symlink itself. For recursive operations, you have three options: default behavior doesn't follow symlinks in subdirectories, -L follows all symbolic links, and -H follows only command-line symlinks. Understanding these options is crucial for managing permissions in directories with complex symlink structures.
Note: On most Linux systems, symlink ownership is largely ignored by the permission system (symlinks typically have rwxrwxrwx permissions for all users). What matters is the ownership and permissions of the target file. However, some special filesystems and security modules may care about symlink ownership.

Example 6: Changing Group on Web Server Content

# Common scenario: Setting up web content permissions
$ sudo ls -l /var/www/html/
total 16
-rw-r--r-- 1 root root 4096 Nov 24 08:00 index.html
-rw-r--r-- 1 root root 2048 Nov 24 08:00 about.html
drwxr-xr-x 2 root root 4096 Nov 24 08:00 css
drwxr-xr-x 2 root root 4096 Nov 24 08:00 images

# Change group to www-data (web server user) recursively
$ sudo chgrp -R www-data /var/www/html/

# Verify the changes
$ sudo ls -l /var/www/html/
total 16
-rw-r--r-- 1 root www-data 4096 Nov 24 08:00 index.html
-rw-r--r-- 1 root www-data 2048 Nov 24 08:00 about.html
drwxr-xr-x 2 root www-data 4096 Nov 24 08:00 css
drwxr-xr-x 2 root www-data 4096 Nov 24 08:00 images

# Also set group permissions to allow web server to read
$ sudo chmod -R g+r /var/www/html/
$ sudo chmod -R g+X /var/www/html/ # Execute on directories only

# Add developers to www-data group for easy editing
$ sudo usermod -a -G www-data craig
$ groups craig
craig : craig wheel developers www-data
Explanation: A common real-world scenario is setting up proper group ownership for web content. Web servers (like Apache or Nginx) typically run as a specific user (www-data on Debian/Ubuntu, apache on RHEL). By changing the group ownership of web content to match the web server's group and giving that group read permissions, the web server can serve the files. Additionally, by adding developer users to the www-data group, they can edit files directly without needing root privileges. This example shows the complete workflow: changing group ownership, setting appropriate permissions, and adding users to the group.
Security Best Practice: For web content, typically the files should be owned by a developer/admin user but have group ownership set to the web server's group. The web server should have read access (and execute on directories) but not write access. This prevents the web server from modifying its own code if compromised.

Example 7: Using chgrp in Scripts with Error Handling

$ cat setup_project.sh
#!/bin/bash

# Script to set up project directory with proper group ownership

PROJECT_DIR="/home/shared/newproject"
PROJECT_GROUP="developers"

# Check if group exists
if ! getent group "$PROJECT_GROUP" > /dev/null 2>&1; then
echo "Error: Group $PROJECT_GROUP does not exist"
exit 1
fi

# Check if directory exists
if [ ! -d "$PROJECT_DIR" ]; then
echo "Error: Directory $PROJECT_DIR does not exist"
exit 1
fi

# Change group ownership
if chgrp -R "$PROJECT_GROUP" "$PROJECT_DIR"; then
echo "Successfully changed group of $PROJECT_DIR to $PROJECT_GROUP"
# Also set setgid bit so new files inherit group
chmod -R g+s "$PROJECT_DIR"
echo "Set setgid bit on directories"
else
echo "Error: Failed to change group ownership"
exit 1
fi

# Report on changes
echo "Directory setup complete:"
ls -ld "$PROJECT_DIR"

$ sudo bash setup_project.sh
Successfully changed group of /home/shared/newproject to developers
Set setgid bit on directories
Directory setup complete:
drwxr-sr-x 5 root developers 4096 Nov 24 08:30 /home/shared/newproject
Explanation: This example shows proper error handling when using chgrp in scripts. The script validates that the group exists using getent group, checks that the directory exists, and tests the return code of chgrp to ensure it succeeded. Additionally, it sets the setgid bit on directories (chmod g+s), which causes new files created in those directories to inherit the directory's group ownership rather than the creating user's default group. This is crucial for maintaining consistent group ownership in shared directories. Always include such validation and error handling in production scripts.
Setgid Bit: The setgid bit (s in the group execute position) on directories is extremely useful for shared project directories. When set, new files and subdirectories created within inherit the directory's group rather than the user's primary group. Combined with proper permissions, this enables seamless collaboration.

Example 8: Preserving Root Ownership with Selective Changes

# Scenario: System directory where some files should stay root-owned
$ sudo ls -l /etc/app/
total 32
-rw-r--r-- 1 root root 2048 Nov 24 08:00 app.conf
-rw-r--r-- 1 root root 1024 Nov 24 08:00 database.conf
-rw-r--r-- 1 root users 4096 Nov 24 08:00 users.conf
-rw-r--r-- 1 root users 8192 Nov 24 08:00 settings.conf
-rwxr-xr-x 1 root root 16384 Nov 24 08:00 init.sh

# Change only user-editable configs to a specific group
$ sudo chgrp appusers /etc/app/users.conf /etc/app/settings.conf

$ sudo ls -l /etc/app/
total 32
-rw-r--r-- 1 root root 2048 Nov 24 08:00 app.conf
-rw-r--r-- 1 root root 1024 Nov 24 08:00 database.conf
-rw-r--r-- 1 root appusers 4096 Nov 24 08:00 users.conf
-rw-r--r-- 1 root appusers 8192 Nov 24 08:00 settings.conf
-rwxr-xr-x 1 root root 16384 Nov 24 08:00 init.sh

# Or use find to select specific file types
$ sudo find /etc/app -name "*.conf" -not -name "app.conf" -not -name "database.conf" -exec chgrp appusers {} \;

# Verify critical files remain root-owned
$ sudo ls -l /etc/app/{app,database}.conf
-rw-r--r-- 1 root root 2048 Nov 24 08:00 /etc/app/app.conf
-rw-r--r-- 1 root root 1024 Nov 24 08:00 /etc/app/database.conf
Explanation: In system directories, you often need selective group ownership changes. Some files (like critical system configs or executables) should remain strictly root-owned, while others can be delegated to specific groups. This example shows explicitly listing only the files to change, rather than using recursive operations that might affect everything. You can also combine find with chgrp using -exec to selectively change groups based on filename patterns, file types, or other criteria. This approach is safer than recursive changes when working with system directories.
Security Warning: Never recursively change group ownership on system directories like /etc, /usr, or /var without careful consideration. Changing ownership of critical system files can break your system or create security vulnerabilities. Always be selective and test in non-production environments first.

Example 9: Group Management for Shared Development Directories

# Create a shared project structure
$ sudo mkdir -p /projects/webapp/{src,docs,tests,deploy}
$ sudo chgrp -R developers /projects/webapp
$ sudo chmod -R 2775 /projects/webapp

# The 2 in 2775 sets the setgid bit
$ ls -ld /projects/webapp/*
drwxrwsr-x 2 root developers 4096 Nov 24 08:30 /projects/webapp/deploy
drwxrwsr-x 2 root developers 4096 Nov 24 08:30 /projects/webapp/docs
drwxrwsr-x 2 root developers 4096 Nov 24 08:30 /projects/webapp/src
drwxrwsr-x 2 root developers 4096 Nov 24 08:30 /projects/webapp/tests

# Notice the 's' in group permissions - that's setgid

# When a developer creates a file, it inherits the group
$ touch /projects/webapp/src/newfile.py
$ ls -l /projects/webapp/src/newfile.py
-rw-rw-r-- 1 craig developers 0 Nov 24 08:35 /projects/webapp/src/newfile.py

# Even though craig's primary group is 'craig', the file is in 'developers'
$ id -gn craig
craig

# Create subdirectory - it also inherits group and setgid
$ mkdir /projects/webapp/src/modules
$ ls -ld /projects/webapp/src/modules
drwxrwsr-x 2 craig developers 4096 Nov 24 08:36 /projects/webapp/src/modules
Explanation: This example demonstrates setting up a collaborative project directory with proper group ownership and permissions. The key elements are: (1) Setting group ownership to the development team's group, (2) Setting permissions to 2775 where the leading 2 sets the setgid bit, 7 gives full permissions to owner, 7 gives full permissions to group, and 5 gives read/execute to others. The setgid bit ensures all new files and directories created within inherit the parent directory's group ownership. This is essential for team collaboration as it prevents the common problem where each user's files have their personal group, making it difficult for teammates to modify them.
Recommended Permissions for Shared Directories:
  • 2770: Collaborative, no world access (most secure for team projects)
  • 2775: Collaborative, world can read and traverse (good for docs)
  • 2777: Fully open (rarely recommended, use with caution)

Example 10: Troubleshooting Group Ownership Issues

# Problem: User can't access a file they should have access to
$ cat /shared/data.txt
cat: /shared/data.txt: Permission denied

# Check current ownership and permissions
$ ls -l /shared/data.txt
-rw-r----- 1 root datagroup 1024 Nov 24 08:00 /shared/data.txt

# Check if user is in the group
$ groups
craig wheel developers

# Problem: User is not in 'datagroup'
# Solution: Add user to group (requires root)
$ sudo usermod -a -G datagroup craig

# User needs to log out and back in, or use newgrp
$ newgrp datagroup
$ groups
datagroup wheel developers craig

# Now change the file if needed
$ sudo chgrp datagroup /shared/data.txt

# Verify access works
$ cat /shared/data.txt
This is the data file content.

# Diagnostic commands
$ id # Shows UID, GID, and all groups
uid=1000(craig) gid=1000(craig) groups=1000(craig),10(wheel),1001(developers),1002(datagroup)

$ getent group datagroup # Shows group members
datagroup:x:1002:craig,john,jane

# Find all files owned by a specific group
$ find /shared -group datagroup -ls

# Find files with wrong group ownership
$ find /shared -not -group datagroup -ls
Explanation: This comprehensive troubleshooting example walks through a common scenario: a user can't access a file even though they should be able to. The diagnostic process includes: checking file ownership and permissions with ls -l, verifying group membership with groups, using id for detailed user information, checking group membership with getent group, and using find to locate files with specific or incorrect group ownership. The solution involves adding the user to the appropriate group with usermod, and the user must either log out/in or use newgrp for the change to take effect in their current session.
Important: Group membership changes don't take effect until the user starts a new session. Running newgrp groupname starts a new shell with that group as the primary group, but logging out and back in is more thorough and is what's typically needed for services and GUI applications.

Common Options

Option Description Example
-R, --recursive Change files and directories recursively chgrp -R devs /project
-v, --verbose Output a diagnostic for every file processed chgrp -v wheel file.txt
-c, --changes Like verbose but report only when change is made chgrp -c devs *.txt
-f, --silent, --quiet Suppress most error messages chgrp -f devs files/*
--reference=RFILE Use RFILE's group rather than specifying a GROUP value chgrp --reference=file1 file2
-h, --no-dereference Affect symbolic links instead of referenced files chgrp -h devs mylink
-H Follow command-line symlinks (with -R) chgrp -R -H devs /dir
-L Follow all symbolic links (with -R) chgrp -R -L devs /dir
-P Do not follow any symbolic links (default) chgrp -R -P devs /dir

Related Commands

Best Practices and Tips

1. Use Setgid for Shared Directories

Always set the setgid bit (chmod g+s) on shared directories after changing their group. This ensures new files inherit the directory's group:

sudo chgrp -R developers /shared/project
sudo chmod -R 2775 /shared/project
2. Verify Group Membership First

Before changing files to a group, verify users are actually members:

getent group developers
groups username
3. Use --reference for Consistency

When you want to match existing ownership, use --reference instead of manually specifying groups:

chgrp --reference=existing_file new_file1 new_file2
Common Mistakes to Avoid:
  • Running recursive chgrp on system directories without careful consideration
  • Forgetting that group membership changes require logout/login to take effect
  • Not setting setgid bit on collaborative directories
  • Changing groups without verifying group exists and users are members
  • Using numeric GIDs in scripts (not portable across systems)

Exit Status

Code Meaning
0 Success - group ownership changed
1 Failure - permission denied, group doesn't exist, or file not found