Dave Dave - 3 months ago 8
Bash Question

Checking Regular File and Directory Ownership and Group Membership in a Bash Shell Script

I am writing shell scripts in Bash 3.2.57(1)-release under Solaris 10 (uname -a yields "SunOS hostname 5.10 Generic_150400-35 sun4v sparc sun4v").

The ultimate problem I'm trying to solve is, within a bash shell script, determining the owner and group membership of a regular file or directory.

Unfortunately, stat is not available to me.

With stat unavailable, the next best thing I know of is parsing the owner and group membership out of the output of ls -l. I do not like this approach in case portability ever becomes an issue and in case I ever come across filenames with special characters in them that throw the parsing off. But, parsing the output of ls -l is what I've got at the moment...

This leads to two questions.

QUESTION ONE



In the absence of stat and with the condition of excluding ls -l as part of the solution, is there an accepted, not-too-hackish way to determine the owner and group membership of a regular file or directory on my specific platform (Bash 3.2.57(1)-release under Solaris 10)?

In Googling around, this does seem to be a real challenge.

If anyone has suggestions on alternatives to parsing ls, I'd sure appreciate hearing them.

QUESTION TWO



Here is my current best attempt via the parsing of the output of ls -l:

#!/usr/bin/bash

###
###
###
# This functions returns success if:
# 1. The ownership of the pass file is root AND
# 2. The group membership of the passed file is root
#
# This function returns failure otherwise.
function check_if_ownership_and_group_membership_are_root
{
if [[ $# -ne 1 ]]; then
echo
echo "Usage: ${FUNCNAME[0]} <filename>"
echo "Actual (incorrect) usage: ${FUNCNAME[0]} $*"
echo "ABORTING SCRIPT; Failure point is designated \"Point 1\""

exit 1
fi

local FILENAME="${1}"

# Check ownership of "${FILENAME}".
if [[ $(ls -l "${FILENAME}" | awk '{print $3}')="root" ]]; then
echo
echo "Part 1: Test of ownership being root supposedly passed"
echo "Actual ownership: " $(ls -l "${FILENAME}" | awk '{print $3}')

# The test of ownership being root passed. Continue on to test the group membership being root.
else
echo
echo "Part 2: Test of ownership being root supposedly failed"
echo "Actual ownership: " $(ls -l "${FILENAME}" | awk '{print $3}')

# The test of ownership being root did not pass. Return failure.
return 1
fi

# Check the group membership of "${FILENAME}".
if [[ $(ls -l "${FILENAME}" | awk '{print $4}')="root" ]]; then
echo
echo "Part 1: Test of group membership being root supposedly passed"
echo "Actual group membership: " $(ls -l "${FILENAME}" | awk '{print $4}')

# The ownership test previously passed, and now the group membership test passed.
# Return success.
return 0
else
echo
echo "Part 2: Test of group membership being root supposedly failed"
echo "Actual group membership: " $(ls -l "${FILENAME}" | awk '{print $4}')

# The test of group membership being root did not pass. Return failure.
return 1
fi

# Should never be able to get here. Abort the script.
echo
echo "ABORTING SCRIPT; Failure point is designated \"Point 2\""
exit 1
}

# Show what ls is being invoked.
echo "Here is what ls will be used:"
type ls

# For this example, I'll just use ad hoc file test.txt to demonstrate the problem I'm having.
FILENAME=./test.txt
touch "${FILENAME}"

###
###
###
# Test the success case of the file ownership being root and the file group membership being root.
chown root "${FILENAME}"
chgrp root "${FILENAME}"

# Display the actual file ownership and group membership.
echo
echo "Test of success case starting; here's the file being tested:"
ls -l "${FILENAME}"

# Perform the check of ownership being "root" and group membership being "root".
if check_if_ownership_and_group_membership_are_root "${FILENAME}"; then
echo
echo "FINAL RESULT: SUCCESS"
else
echo
echo "FINAL RESULT: FAILURE"
fi

###
###
###
# Test the failure case of the file ownership not being root or the file group membership not being root.
chown nobody "${FILENAME}"
chgrp other "${FILENAME}"

# Display the actual file ownership and group membership.
echo
echo "Test of failure case starting; here's the file being tested:"
ls -l "${FILENAME}"

# Perform the check of ownership being "root" and group membership being "root".
if check_if_ownership_and_group_membership_are_root "${FILENAME}"; then
echo
echo "FINAL RESULT: SUCCESS"
else
echo
echo "FINAL RESULT: FAILURE"
fi


This results in the following output:

bash-3.2# ./script.sh
Here is what ls will be used:
ls is /usr/bin/ls

Test of success case starting; here's the file being tested:
-rw------- 1 root root 16 Aug 25 13:34 ./test.txt

Part 1: Test of ownership being root supposedly passed
Actual ownership: root

Part 1: Test of group membership being root supposedly passed
Actual group membership: root

FINAL RESULT: SUCCESS

Test of failure case starting; here's the file being tested:
-rw------- 1 nobody other 16 Aug 25 13:34 ./test.txt

Part 1: Test of ownership being root supposedly passed
Actual ownership: nobody

Part 1: Test of group membership being root supposedly passed
Actual group membership: other

FINAL RESULT: SUCCESS


As can be seen, the conditions I'm testing with the "if" statements always pass. What am I doing wrong?

(Even though I'm hoping someone can guide me away from parsing ls, I'd still like to know the answer to this question in any case for education's sake.)

Sincere thanks to all responders in advance.

Answer

You need spaces around the comparison operator =:

[[ $(ls -l "${FILENAME}" | awk '{print $4}') = "root" ]]

Also, you should use == instead of =, when you write the condition with double brackets [[ ... ]].