Rocket U2 | UniVerse & UniData

 View Only

 Reading file names and date/time from an AIX directory and comparing with UniVerse records.

Greg Clitheroe's profile image
Greg Clitheroe posted 08-19-2024 21:10

Using a BASIC program, I need to read filenames and file dates from an AIX directory and compare them with names and dates held in UniVerse records. If the files are present among the UniVerse records then they need to be moved out of the directory and more files added from another directory. Any advice or code snippets much appreciated.

Joe Goldthwaite's profile image
Joe Goldthwaite

It's really simple to do this directly in python.  I've wrote a utility that goes compares the dates of all the files in my BP folders with the dates in the BP.O folders and lists any where the object code is older than the source code. That indicates that the source has been changed without being recompiled.

I checked and the FILEINFO function doesn't give the modification date and time at least on the Unverse 11.4 release I'm running.  I think the easiest way to do it would be to execute a Unix command and capture the result. You can execute Unix commands from Universe with the SH command.  Here's a sample program to illustrate it:

PATH = '/source/programs/BP.JG/X'
COMMAND = 'SH -c "stat ':PATH:'"'
EXECUTE COMMAND CAPTURING OUTPUT
PRINT CHANGE(OUTPUT, @AM, CHAR(13):CHAR(10))
COMMAND = \SH -c "ls -al --time-style=+'%Y-%m-%d %H:%M' /source/programs/BP.JG | grep X"\
EXECUTE COMMAND CAPTURING OUTPUT
PRINT CHANGE(OUTPUT, @AM, CHAR(13):CHAR(10))
STOP

The stat command shows all the file statistics including date and time:

  File: ΓÇÿ/source/programs/BP.JG/XΓÇÖ
  Size: 1240            Blocks: 8          IO Block: 4096   regular file
Device: fd03h/64771d    Inode: 17475       Links: 1
Access: (0777/-rwxrwxrwx)  Uid: ( 1000/   jgold)   Gid: ( 1004/ barsdev)
Access: 2024-08-19 20:43:38.681007311 -0500
Modify: 2024-08-19 20:43:38.608000548 -0500
Change: 2024-08-19 20:43:38.608000548 -0500
 Birth: -

If you need multiple files at once the ls command will show them all. The "-al"  option lists detail including the modification date. The --time-style option forces the dates to a fixed format. Without that you have to deal with Linux/Unix habit of not showing the year if it's in the current year and showing the time instead. 

You end up with something like this:

-rwxrwxrwx+  1 jgold barsdev   214 2024-07-30 12:18 AUTOEXEC.BAT
-rwxrwxrwx+  1 jgold barsdev    89 2004-02-25 18:36 BOX
-rwxrwxrwx+  1 jgold barsdev  2287 2004-02-25 18:36 CHECK.XMIT
-rwxrwxrwx+  1 jgold barsdev  4597 2004-02-25 18:36 CURSOR.TXT
-rwxrwxrwx+  1 jgold barsdev 52210 2004-02-25 18:36 DEPR.TXT
-rwxrwxrwx+  1 jgold barsdev   982 2004-02-25 18:36 DRAW.LASER.BOX
-rwxrwxrwx+  1 jgold barsdev   610 2004-02-25 18:36 FIX.BASIC.CATALOGS
-rwxrwxrwx+  1 jgold barsdev   726 2004-02-25 18:36 GET.UNIX.NAME
-rwxrwxrwx+  1 jgold barsdev 15497 2004-02-25 18:36 GLCHART.TXT
-rwxrwxrwx+  1 jgold barsdev    26 2004-02-25 18:36 STX
-rwxrwxrwx+  1 jgold barsdev  1271 2024-08-19 20:54 X
-rwxrwxrwx+  1 jgold barsdev    27 2004-02-25 18:36 XX

All you have to do is parse OUTPUT to get the data you need.  There may be variations on the output with AIX but this should still work.

Greg Clitheroe's profile image
Greg Clitheroe

Looks like I picked the wrong kind of thread so I can't reply to Joe's useful answer.

I've only done trivial BASIC programming because I do most of my data manipulation in UniVerse SQL. I've never explored the other languages supported by UniVerse.

Am I to understand that code can be written in Python then compiled in much the same way as compiling BASIC and the program will be available to UniVerse just like a BASIC  subroutine? I have to be able to run it like that due to the way the front end scheduling program calls the action.


John Jenkins's profile image
John Jenkins

Greg,

You can add Python functions to UniVerse and invoke them in much the the same way as BASIC subroutines. There are examples in the default XDEMO account of both BASIC programs that call Python and the associated Python code. You can also execute Python programs directly from ECL or by running a Python shell using "SH -c .......".

Python functionality is licensed but has no charge, if you don't have it just ask your UniVerse supplier to add it.

There is much more functionality outside the restrictive SQL environment than in SQL's straitjacket.

Regards

JJ

Mark Sapp's profile image
ROCKETEER Mark Sapp

This is where BASIC really shines, is with string handling.  I needed to build some cleanup routines, for example a utility to delete any files in the _PH_ directory that are over 2 days old. Although you can create a DIR pointer where each filename in the directory appears as the record key, you need to go to the OS level to get the date / time stamp.  I built a subroutine that can provide the calling program a list (array) of filenames and their associated date stamp, allowing the calling program to look through the list and take action based on the date.  Note that AIX may have a different format to the output and the parsing code may need to be tweaked.  This was written in Unidata,  but I believe it should work in Universe as well.  There may be more elegant solutions, but this took 10 minutes to create and does the job :-)

SUBROUTINE OSDIR.INFO(DIRNAME,FILELIST)
* Unidata file date subroutine * Rocket Software * msapp * 12/10/2019
* Returns an associated list - FILELIST<1,nn> = file name and FILELIST<2,nn> = internal date
* For FILE cleanup, you can compare the date to your threshold to determine if the file should be deleted
* Use with caution !!!  Note: Used against Linux OS, other unix variants could need different parsing

BEGIN CASE
  CASE DIRNAME[1,2] = "./" ;* one level down 
   * OK, no action needed
  CASE DIRNAME[1,1] = "/"  ;* Assumes full path
  * OK, no action needed
  CASE DIRNAME[1,1] = "."  ;* Second char is not '/' so add it in  
    DIRNAME = "./":DIRNAME[2,LEN(DIRNAME)]
  CASE 1
    DIRNAME = "./":DIRNAME
END CASE
* Get list of files with date stamp at OS level
PCMD = "ls -l --time-style=long-iso ":DIRNAME
PCPERFORM PCMD CAPTURING PRISONERS
*
FLIST = TRIM(PRISONERS)
LNS = DCOUNT(FLIST,@FM)
TD = DATE()
THIS.YR = OCONV(TD,"DY")
*
CNTR = 0
FILELIST = ""
*
FOR X = 1 TO LNS
  THIS.LINE = FLIST<X>
  THIS.DATE = FIELD(THIS.LINE," ",6)
  * Current year will not contain year in the date stamp
  MM = FIELD(THIS.DATE,"-",3)
  DD = FIELD(THIS.DATE,"-",2)
  YY = FIELD(THIS.DATE,"-",1)
  IF INDEX(YY,":",1) > 0 THEN YY = THIS.YR
  ODATE = DD : " " : MM : " " : YY
  FNAME = FIELD(THIS.LINE," ",8)
  IF FNAME[1,1] = "." THEN CONTINUE
  IF FNAME[1,1] = " " THEN CONTINUE
  IF FNAME = "" THEN CONTINUE
  *
  IDATE = ICONV(ODATE,"D")
  CNTR +=1
  FILELIST<1,CNTR> = FNAME
  FILELIST<2,CNTR> = IDATE  
NEXT X
*
RETURN

You can test this by creating a test program:

CRT "* Get file list *"

CRT "Enter DIR name: ":

INPUT FNAME

FILELIST = ""

CALL OSDIR.INFO(DIRNAME,FILELIST)

LCNT = DCOUNT(FILELIST,@AM)

FOR X = 1 TO LCNT

  PRINT FIELDLIST<X,1> :  " - " : OCONV(FILELIST<X,2>,"D4/")

NEXT X

Joe Goldthwaite's profile image
Joe Goldthwaite

Hi Greg,

That's a good approach and a good example of how to parse the output.

Since the &PH& file is a folder or type 19 file you can purge it directly in the OS using the find command. This should work on AIX:

find "[your acct path]/&PH&" -type f -mtime +2 -exec rm {} \;

Replace [your acct path] with the path to the account with your &PH& file.  The & is a logical operator in the Unix shell so it's important to put the folder name in quotes.

I tested this on the &PH& file in the main account of my development system and didn't put it in quotes. It listed all the data files in the account. Luckily for me I tested the find command first by leaving off the "=exec rm[] \" or I would have deleted all those files and be restoring everything from backup. So leave off the "-exec rm" until you're sure you're getting a valid list of files.

You can automate it by adding the line to your crontab file

00 01 * * * root find "[your acct path]/&PH&" -type f -mtime +2 -exec rm {} \;

Using OS functions where you can makes things simpler and easier to maintain. It is scary though. When I executed the command the first time without putting it in quotes and saw all my files instead of just the ones it the &PH& file it gave me the shivers.

Martin Shields's profile image
PARTNER Martin Shields

I note that you're asking about an AIX system, and so Joe's original answer would need some modifications for it to work. For one, the "stat" would need to be replaced with "istat" which produces a slightly different output format:

# istat /tmp/cnt.pl
Inode 120 on device 10/7        File
Protection: rwxr-xr-x
Owner: 0(root)          Group: 0(system)
Link count:   1         Length 382 bytes

Last updated:   Thu Jul  6 08:46:09 2023
Last modified:  Thu Jul  6 08:46:09 2023
Last accessed:  Tue Aug  6 22:19:49 2024

For another, the "ls" command lacks the "--time-style" option.

Were you to use Python for this, and needed any of the stat/istat info rather than just the date provided by the "ls -l" command, you would use the "stat" function (via "from os import stat").

  

David Green's profile image
David Green

To make it easy, just use UniData command DIR(FilePath).

Check out my version here: https://www.dagconsulting.com/GET_DIR_INFO.txt

I use it as an I-Descriptor on the _PH_ file (any DIR type file will work)  And call it Date_Added.

Then all you have to do is SELECT _PH_ WITH Date_Added LE "Yesterday's Date".  Then DELETE.