Help regarding shell script

Hello,

When listing the file systems (using ls -ltr) , if the group names are longer the group name is getting truncated.

Can someone help with the script which would display the truncated group name?

I appreciate if someone could help in this regard.

How about using ls -n and looking the gid up in /etc/group yourself.

Hi Chubler,

Thanks for your reply. But for making all the users to view their complete group names in the listing it would be tougher to do that everytime. So having a script in the root .profile would let the user to have the complete group name displayed.

Thanks
Mike

The format of ls -n output varies from system to system, can you supply a example output as the awk script will need to use substrings to extract the gid and uid but keep the other column spacing the same.

---------- Post updated at 11:54 AM ---------- Previous update was at 11:34 AM ----------

For my system UID + GID starts at char 16 and is 13 chars long below function is based on this, change S and L below for your ls output.

The script calculates the maximum UID and GID lengths in the system and adjusts column widths based on this. So beware if you add a new group or user to the system with a longer ID the column sizes in this output will change.

ls -nrt /my/path/to/directory | awk -vS=16 -vL=13 '
function max(a,b) {return a>b?a:b}
FNR==1 {file++}
file==1 {g[$3]=$1;GW=max(GW,length($1));next}
file==2 {p[$3]=$1;PW=max(PW,length($1));next}
{ split(substr($0,S,L), ID, " ");
  printf "%s %-*s %-*s%s\n", substr($0,1,S-1), PW, p[ID[1]], GW, g[ID[2]],substr($0,S+L)
}' FS=: /etc/group /etc/passwd -

If I enter ls -ltra I will get the output of the groupname in this truncated format

              uid              Group name                           
-rw-r--r--  1 Mike     Functional-Wi......   20480 Sep 19  2007 first.tar  

but i would like to see the output in the following format

              uid                    Group name                           
-rw-r--r--  1 Mike Functional-Wireless-Consumers    20480 Sep 19  2007 first.tar

Yes, that's what the above script does, it relies on the output of ls -n (Long format with numeric userID and groupID) and reads passwd and group files to expand the full names.

Can you supply the output of ls -ntra within

```text
 and 
```

tags?

Thanks a lot for the reply. When I run your script I get the following:

drwxr-xr-x 3 10   Functional-Wireless-Consumers      2011-01-03 23:29 install-media
drwx------ 2 10   Functional-Wireless-Consumers      2011-01-04 18:05 Downloads
drwxr-xr-x 2 10   Functional-Wireless-Consumers      2011-01-04 23:19 Desktop
-rwxrwxrwx  10   Functional-Wireless-Consumers      2011-01-31 21:24 list.sh

Can you please explain me the code and I was unable to get the one which you have asked for?

Thank You

That is because your ls output is slightly different to mine (this is quite likely if you are on a different OS to me).

This is why I need the output of ls -ntra on your system so I could adjust the values of S (start) and L (length) for your system.

Again please use the

```text
 and 
```

tags around your posting of the ls -ntra output so the forum dosn't strip spaces as these are important in determining character positions for the columns.

Hi Chubbler,

I couldn't access my server for some reason it is down I guess. I was trying for a while but I couldn't. But I for the awk script I was using in this fashion

[awk '{printf "%-12s %6s %-16s %-22s %8s %-4s %3s  \n", $1, $2, $3, $4, $5, $6, $7}']

Let me know if this should be good and can you please run me through your code about the function you declared and about the substrings you wrote. Sorry I'm finding bit tougher to get understand the process.

Thanks a lot for your help in this issue.

Ok the function max(a,b) returns the maximum of two integers, ie highest of a or b.

FNR==1 {file++} This says if file line number is 1 (first line of the file) then increment file variable. This is used to test what file is being processed 1=/etc/group 2=/etc/passwd 3=ls output.

file==1 {g[$3]=$1;GW=max(GW,length($1));next} This loads the group file into the has array g[] with the group id (field 3) as the key and group name (field 1) as the data. It also uses the max(a,b) function to set GW as maximum length of groupname.

file==2 {p[$3]=$1;PW=max(PW,length($1));next} same as group above except hash array is p[] and PW is maximum login.

{ split(substr($0,S,L), ID, " ");
  printf "%s %-*s %-*s%s\n", substr($0,1,S-1), PW, p[ID[1]], GW, g[ID[2]],substr($0,S+L) }

This extracts the UID and GID from the ls output by fetching a substring from S to S+L and spliting it up using space seperators into ID[1] and ID[2] variables.
The string from 0-S is printed
The ID[1] (UID) field is looked up in the P[] hash array and the loginID is fetched, this is printed left justified to a width of PW.
The ID[2] (GID) field is looked up in the G[] hash array and the GroupName is fetched, this is printed left justified to a width of GW.
The the rest of the ls string from S+L to the end is printed.

Hi,

This is what I get when I type ls -ntra

-rwxrwxr-x    1 1750560623 1750560023        110 Jan 27 12:21 list.sh
-rwxr-x---    1 1750560623 1750560023         80 Jan 28 09:25 .desk
drwxrwxr-x 201 0              1750560001        22324 Jan 29 10:12 uni_his

Damn, the length of the UID and GID fields are so long they have pushed out the alignment of all the following columns.

Best idea to fix this is to re-format all the fields up to field 5 and then use the raw ls string from there. The format ls uses for dates varies in width and number of elements depending on when the date is (e.g. older than 1 year or future dates also have YYYY). Not to mention filenames with spaces, etc. So it's best to just substring out the ls output after filesize and print it as-is.

I've added a function toend(str, n) that strips the first n space separated fields from the front of a string. We use toend($0,5) to get the date and filename part of the ls listing.

ls -nrt /my/path/to/directory | awk 'function max(a,b) {return a>b?a:b}
function toend(str,fld)
{ for(i=0; i<length(str); i++) {
    while(substr(str,i,1) != " " && i<length(str)) i++
    while(substr(str,i,1) == " " && i<length(str)) i++
    if (!--fld) return substr(str,i)
  }
  return ""
}
FNR==1 {file++}
file==1 {g[$3]=$1;GW=max(GW,length($1));next}
file==2 {p[$3]=$1;PW=max(PW,length($1));next}
{ split($0, L, " ")
  printf "%10s %3s %-*s %-*s %11s %s\n", L[1], L[2], PW, p[L[3]], GW, g[L[4]], L[5], toend($0,5)
}' FS=: /etc/group /etc/passwd -

Hi Chubler,

Thanks again. The main issue is I cant put it in my path, I have to put this code in .profile so that any user who types ls should have the longlist group name ( Just the groupname which i have mentioned functional-wireless- consumer) displayed.

And I have to put it as alias in .profile as,

[alias mike="/path/directory/UID/and the SCRIPT.sh"]

so that if any user who types in mike would have the complete long list groupname displayed.

Please let me know about the workaround on this.

Thanks
Mike

OK take the final script I posted above and replace the 1st line with these two:

#!/bin/sh
ls -n $@ | awk '

Save this to /path/directory/UID/newls.sh (for example)

Then in the user's .profile put alias mike="/path/directory/UID/newls.sh"

Now you should be able to do stuff like:

$ mike $HOME
$ mike -d /tmp
$ mike -rt $HOME

Hi,

After running the code as you have sent I get the following output. I have attached the code too below. Sorry for the inconvenience since I'm a newbie to this :slight_smile:

Hi,

I tried as you have mentioned but I get something of this format in the output

OUTPUT

$ ./lan.sh -->
         3     #
       RUN     #
     a.ksh     #
     a.txt     #
ktrace.out     #
    lan.sh     #
        lp     #
  msa.ksh     #

and this was the code I put in the script lan.sh

[#!/bin/sh
ls -n $@ | awk 'function max(a,b) {return a>b?a:b}
function toend(str,fld)
{ for(i=0; i<length(str); i++) {
    while(substr(str,i,1) != " " && i<length(str)) i++
    while(substr(str,i,1) == " " && i<length(str)) i++
    if (!--fld) return substr(str,i)
  }
  return ""
}
FNR==1 {file++}
file==1 {g[$3]=$1;GW=max(GW,length($1));next}
file==2 {p[$3]=$1;PW=max(PW,length($1));next}
{ split($0, L, " ")
  printf "%10s %3s %-*s %-*s %11s %s\n", L[1], L[2], PW, p[L[3]], GW, g[L[4]], L
[5], toend($0,5)
}' FS=: /etc/group /etc/passwd -

Appreciate your help in this matter.

---------- Post updated 02-02-11 at 04:42 PM ---------- Previous update was 02-01-11 at 09:27 PM ----------

Hi,

The following is the output I get after running the code. I get blank spaces in the output. Can you please help me on this?

[$ ./list.sh
     total  56
-rwxrwxr-x   1                              284 Feb 02 11:08 app
-rwxrwxr-x   1                              284 Feb 02 09:28 list
-rwxrwxr-x   1                              168 Jan 27 14:31 desk
-rwxrwxr-x   1                              668 Feb 02 09:24 lan.sh

It's not finding UID and GID in the passwd/group files, perhaps you're using yellow pages (NIS) for the users and groups?

If so you may need to fetch the group and passwd files from NIS first:

#!/bin/sh
cp /etc/group /tmp/lan.group.$$
ypcat group >> /tmp/lan.group.$$
cp /etc/passwd /tmp/lan.passwd.$$
ypcat passwd >> /tmp/lan.passwd.$$
ls -n $@ | awk 'function max(a,b) {return a>b?a:b}
function toend(str,fld)
{ for(i=0; i<length(str); i++) {
    while(substr(str,i,1) != " " && i<length(str)) i++
    while(substr(str,i,1) == " " && i<length(str)) i++
    if (!--fld) return substr(str,i)
  }
  return ""
}
FNR==1 {file++}
file==1 {g[$3]=$1;GW=max(GW,length($1));next}
file==2 {p[$3]=$1;PW=max(PW,length($1));next}
{ split($0, L, " ")
  printf "%10s %3s %-*s %-*s %11s %s\n", L[1], L[2], PW, p[L[3]], GW, g[L[4]], L
[5], toend($0,5)
}' /tmp/lan.group.$$ /tmp/lan.passwd.$$ -
rm /tmp/lan.group.$$ /tmp/lan.passwd.$$

Hi,

I tried from putty and this was the output I got:

ypcat: no such map passwd.byname. reason: Request arguments bad
./san: 4: Syntax error: "(" unexpected

Thanks
Mike

OK looks you aren't using yellow pages then, are you sure when you got the output in post 15 your code is exactly as shown in post #15 except without the [ at the front?

Missing the FS=: on the last line would have caused this. You could also try this (just incase your awk dosn't support FS= following the main code:

#!/bin/sh
ls -n $@ | awk -F: 'function max(a,b) {return a>b?a:b}
function toend(str,fld)
{ for(i=0; i<length(str); i++) {
    while(substr(str,i,1) != " " && i<length(str)) i++
    while(substr(str,i,1) == " " && i<length(str)) i++
    if (!--fld) return substr(str,i)
  }
  return ""
}
FNR==1 {file++}
file==1 {g[$3]=$1;GW=max(GW,length($1));next}
file==2 {p[$3]=$1;PW=max(PW,length($1));next}
{ split($0, L, " ")
  printf "%10s %3s %-*s %-*s %11s %s\n", L[1], L[2], PW, p[L[3]], GW, g[L[4]], L[5], toend($0,5)
}' /etc/group /etc/passwd -

I will check that again on server and let you know. And when time permits if you could run through the code about the first part in the for and while loop and the printf statement ( the methodology of using % and the nos) to make the output look that would be great.

Thanks again
Mike

for(i=0; i<length(str); i++) i is a counter that starts at 0 and continues to the end of the string (step thru string 1 char at a time).

while(substr(str,i,1) != " " && i<length(str)) i++ Jump over all characters till a space is found, this jumps past 1 field
while(substr(str,i,1) == " " && i<length(str)) i++ Jump over all space characters this jumps past the blanks following a field
if (!--fld) return substr(str,i) decrement field count and if it's now zero return the rest of the string.

%10s = right justified string 10 chars wide
%3s = right justified string 3 chars wide
%-*s = left justified string where width is parameter before string value
%s = string with no width limit

You can check man printf for more details on how it works.