1

I'm using QNX.

I have the following output of ls -l:

drwxr-xr-x   2 root      root           4096 Jul 26  2021 bin

From this, I would want to use sed to extract the user and group, and put these strings into shell variables.

I do not have access to a stat command.

2 Answers2

5

If your shell is a POSIX one, and user and group names don't contain space characters, you can use the split+glob operator (invoked implicitly when you leave parameter expansions, command substitution or arithmetic expansion unquoted in list contexts):

IFS=' ' # split on space only
set -o noglob # disable the glob part
output=$(LC_ALL=C ls -Lld bin) || exit # exit if bin can't be stat()ed.

set -- $output # split+glob $output and assign result to positional parameters

mode=$1 # could also contain +, @... to specify system-dependent extra # information such as the presence of ACLs or extended attributes

links=$2 user=$3 group=$4 size=$5

If you can't guarantee user and group names won't contain space characters, you could use ls -n instead of ls -l and you'd then get the uid and gid in $user and $group which may be enough for your needs.

With sed, you could use it to parse the first line of the output of ls and generate the shell code that sets the variables:

get_credentials() {
  eval "$(
    sp=' \{1,\}' nsp='[^ ]\{1,\}'
    LC_ALL=C ls -Lld -- "${1?}" |
      LC_ALL=C sed -n "
        /^$nsp$sp$nsp$sp\($nsp\)$sp\($nsp\).*$/ {
          s//\1 \2/
          s/'/'\\\\''/g
          s/\($nsp\) \($nsp\)/user='\1' group='\2' ||/p
        }
        q"
    ) false"
}

To be used as:

get_credentials bin || exit
printf 'The %s name is: "%s"\n' user  "$user" \
                                group "$group"

That would evaluate the user='the-user' group='the-group' || false shell code (or user='o'\''connor'... for o'connor for instance) if the user and group names can be extracted from the first line of ls output, or false otherwise.

0

pure sed

  1. gather username

    user=$(ls -ld .| sed 's/^[dlLsStT+@rwx-]*[ 0-9]*\([^ ]*\).*$/\1/')
    
  2. gather goup name

    group=$(ls -ld .| sed -e s/$user// -e 's/^[dlLsStT+@rwx-]*[ 0-9]*\([^ ]*\).*$/\1/')
    

where

  • first sed didn't need -e as only one command
  • ^[dlLsStT+@rwx-]*[ 0-9]* catch file access and size (you may need to add s for socket/ c,b for special file)
  • \([^ ]*\) match and remember username/group name (without space in them of course)
  • .*$ rest of line
  • \1 recall first remembered pattern

Note :

  • this will fail if user is rwx (or any combination matching access bit)
  • as Stéphane Chazelas pointed out, this relay on username and group name being "normal".
Archemar
  • 31,554
  • 1
    The first field may also contain some lLsStT+@ characters (but no backslash), not just drwx-. – Stéphane Chazelas Aug 13 '21 at 12:11
  • Both would strip characters ranging between 0 and 9 from the start of the username. While it's not common to have user names starting with digits (or other characters ranging between 0 and 9 which generally are not ASCII ones), ls -l could put uids/gids there which are all numeric, when it can't resolve those ids to names. – Stéphane Chazelas Aug 13 '21 at 12:15
  • That sed -e s/$user// is a bit brittle and not foolproof and not only because you forgot the quotes. What if $user is rwx, a number, or contains / or regexp operators? – Stéphane Chazelas Aug 13 '21 at 12:17
  • And I have a problem, RWX can change any time – Дмитрий Гнатюк Aug 13 '21 at 12:20
  • I meant that lLsStT+@ can be part of the permissions, not the file type which for . should be d. For the type of files other than ., there's an even wider ranger of possible characters depending on the system. – Stéphane Chazelas Aug 13 '21 at 12:21