在 Bash Shell 脚本中检查常规文件和目录所有权以及组成员身份

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

我在 Bash 3.2.57(1) 中编写 shell 脚本-在 Solaris 10 下发布(uname -a 产生 "SunOS hostname 5.10 Generic_150400-35 sun4v sparc sun4v")。

我要解决的最终问题是,在 bash shell 脚本中,确定常规文件或目录的所有者和组成员身份。

很遗憾,我无法使用统计数据。

由于 stat 不可用,我知道的下一个最好的事情是从 ls -l 的输出中解析所有者和组成员身份。我不喜欢这种方法,以防万一可移植性成为问题,万一我遇到带有特殊字符的文件名会导致解析失败。但是,解析 ls -l 的输出是我目前得到的...

这引出了两个问题。

问题一

缺少 stat 并且 排除 ls -l 作为解决方案的一部分的情况下,是否有可接受的,在我的特定平台(Bash 3.2.57(1)-Solaris 10 下的发行版)上确定常规文件或目录的所有者和组成员身份的不太老套的方法?

在谷歌搜索中,这似乎是一个真正的挑战。

如果有人对解析 ls 的替代方法有任何建议,我将不胜感激。

问题二

这是我目前通过解析 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=""

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

      # 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 }')

      # 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 }')="root" ]]; then
      echo
      echo "Part 1: Test of group membership being root supposedly passed"
      echo "Actual group membership: " $(ls -l "${FILENAME}" | awk '{print }')

      # 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 }')

      # 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

这导致以下输出:

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

可以看出,我使用 "if" 语句测试的条件总是通过。我做错了什么?

(尽管我希望有人能指导我远离解析 ls,但为了教育起见,无论如何我仍然想知道这个问题的答案。)

在此先感谢所有响应者。

比较运算符两边需要空格 =:

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

另外,当你用双括号[[ ... ]].

写条件时,你应该使用==而不是=

一般不推荐依赖ls的输出

if ! [[ $(stat --format '%G' "${FILENAME}") = "root" ]]; then
    echo "do the thing"
fi

Shellcheck wiki 讨论了依赖 ls 输出的一些陷阱:https://github.com/koalaman/shellcheck/wiki/SC2012

引用:

ls is only intended for human consumption: it has a loose, non-standard format and may "clean up" filenames to make output easier to read.