AWK: nested while loops w/ external commands

For discussions about programming, programming questions/advice, and projects that don't really have anything to do with Puppy.
Post Reply
Message
Author
s243a
Posts: 2580
Joined: Tue 02 Sep 2014, 04:48
Contact:

AWK: nested while loops w/ external commands

#1 Post by s243a »

In the following AWK example we loop through /proc/mounts. For each moing point (e.g. /initrd/mnt/dev_save) we see if the realpath contains the mount point. If so we return the mount point else we continue looping though process/mounts.

If the path is for a device that isn't mounted then we take the the left part of the realpath up until the path is one level deeper than the directory that is named "mnt" in the path. So for example if the following file isn't mounted:

Code: Select all

/initrd/mnt/dev_save/Tiny_Puduan/PreAlpha11.4/puppy_tascii.sfs
then we just use regular expressions to extract the part of the path that looks like the device mount point. In other words we want this part:

Code: Select all

/initrd/mnt/dev_save
Here is the awk code:

Code: Select all

function realpath(p){
  cmd="realpath '" p "'"
  while ((cmd | getline )){
	  rp=$0
	  break
  }
  if (length(rp)>0){
	return rp
  } else {
	print "Warning realpath not found for " p > "/dev/stderr"
    return p
  }	
}
function get_dev_mp(path,    mp,rp,count){
  #cmd="cat /proc/mounts | grep \"$(realpath " dev ")\""
  rp=realpath(path)
  cmd="cat /proc/mounts" # | grep \"$(realpath '" rp "')\""
  while ((cmd | getline )){
	#dev=$1 #don't need this yet
	print "cmd_out=" $0 > "/dev/stderr"
	mp=$2
	cmd2="echo " rp " | grep -c " mp 
	while ((cmd2 | getline )){
	    print "cmd2_out=" $0 > "/dev/stderr"
		count=$0
		break #this is uncessary
    }
    if ( count>0 ){
      return mp
      break
    }
  }
  if (count==0){
      print "Warning: dev not mounted! Inferring dev mount point from path" > "/dev/stderr"
	  mp=gensub(/^(.*[/]mnt[/][^/]*)[/].*/,"\\1",1,rp)
	  return mp
  }
}
/usr/local/psandbox/sb_db_rec_field.awk#L20


Here is the console output:

Code: Select all

path=/initrd/mnt/dev_save/Tiny_Puduan/PreAlpha11.4/puppy_tascii.sfs
cmd_out=/dev/sda2 /initrd/mnt/dev_save ext4 rw,noatime 0 0
cmd2_out=1
dev_mnt_pt=/initrd/mnt/dev_save
The console output comes by printing to stderr.

While it is the case that I am using nested while loops. The inner loop only loops once. The inner loop is necessary because in AWK, the only way (that I know of) to return a value from an external function (other than an exit code), is to pipe the shell command to AWKs getline command. You can read about the getline command at:

https://www.gnu.org/software/gawk/manua ... tline.html

P.S. the project "psandbox" which the above code is part of is not ready for testers even though some features of it appear to work.
Find me on [url=https://www.minds.com/ns_tidder]minds[/url] and on [url=https://www.pearltrees.com/s243a/puppy-linux/id12399810]pearltrees[/url].

musher0
Posts: 14629
Joined: Mon 05 Jan 2009, 00:54
Location: Gatineau (Qc), Canada

#2 Post by musher0 »

Double, sorry.
Last edited by musher0 on Wed 29 Jan 2020, 07:39, edited 1 time in total.
musher0
~~~~~~~~~~
"You want it darker? We kill the flame." (L. Cohen)

musher0
Posts: 14629
Joined: Mon 05 Jan 2009, 00:54
Location: Gatineau (Qc), Canada

#3 Post by musher0 »

Triple, sorry... (The forum editor looked it was jamming, and i became impatient!)
Last edited by musher0 on Wed 29 Jan 2020, 07:43, edited 2 times in total.
musher0
~~~~~~~~~~
"You want it darker? We kill the flame." (L. Cohen)

musher0
Posts: 14629
Joined: Mon 05 Jan 2009, 00:54
Location: Gatineau (Qc), Canada

#4 Post by musher0 »

Hi s243a.

Sorry for being so dumb, but what are you trying to discover or isolate with your
AWK script? Shouldn't there be a variable after the script, of what you are looking for?
E. g. script bebop
(if looking for something called "bebop")

On the other hand, wouldn't

Code: Select all

cat /proc/mounts | grep sda2
enough? (Or bebop, or whatever)

TIA
musher0
~~~~~~~~~~
"You want it darker? We kill the flame." (L. Cohen)

s243a
Posts: 2580
Joined: Tue 02 Sep 2014, 04:48
Contact:

#5 Post by s243a »

musher0 wrote:Hi s243a.

Sorry for being so dumb, but what are you trying to discover or isolate with your
AWK script? Shouldn't there be a variable after the script, of what you are looking for?
E. g. script bebop
(if looking for something called "bebop")

On the other hand, wouldn't

Code: Select all

cat /proc/mounts | grep sda2
enough? (Or bebop, or whatever)

TIA
You can't directly grep for something like "sda2", because you don't know what you are trying to grep for. The device mount point, is a parent folder of the real full path to the file or directory.

I suppose an alternative way to do this though would be to keep navigating one folder higher and trying to grep a line in "proc/mounts". In which case your approach would work but you still need a loop.

However, one advantage of your approach is that the realpath function might succeed in a parent folder but not with the full path. I think I'll make this an "issue" in my project to use your approach but I won't do it right away because my approach works for now.

Edit: Or maybe a hybrid approach would be better, where I only use the navigating to parent folders for the purposes of determining the realpath.
Last edited by s243a on Wed 29 Jan 2020, 07:49, edited 3 times in total.
Find me on [url=https://www.minds.com/ns_tidder]minds[/url] and on [url=https://www.pearltrees.com/s243a/puppy-linux/id12399810]pearltrees[/url].

musher0
Posts: 14629
Joined: Mon 05 Jan 2009, 00:54
Location: Gatineau (Qc), Canada

#6 Post by musher0 »

Not a criticism, BTW. Just trying to understand with the tools I know.
musher0
~~~~~~~~~~
"You want it darker? We kill the flame." (L. Cohen)

s243a
Posts: 2580
Joined: Tue 02 Sep 2014, 04:48
Contact:

#7 Post by s243a »

musher0 wrote:Not a criticism, BTW. Just trying to understand with the tools I know.
No worries. I never considered the possibility that it might be a criticism. I hope my example inspires some interest in using external functions in AWK. :)
Find me on [url=https://www.minds.com/ns_tidder]minds[/url] and on [url=https://www.pearltrees.com/s243a/puppy-linux/id12399810]pearltrees[/url].

musher0
Posts: 14629
Joined: Mon 05 Jan 2009, 00:54
Location: Gatineau (Qc), Canada

#8 Post by musher0 »

Ah, ok.
The realpath and / or readlink utilities are of no use in this case?
musher0
~~~~~~~~~~
"You want it darker? We kill the flame." (L. Cohen)

phat7
Posts: 179
Joined: Fri 05 Jun 2015, 08:54

Re: AWK: nested while loops w/ external commands

#9 Post by phat7 »

s243a wrote:Here is the awk code:

Code: Select all

function realpath(p){
  cmd="realpath '" p "'"
  while ((cmd | getline )){
	  rp=$0
	  break
  }
  if (length(rp)>0){
	return rp
  } else {
	print "Warning realpath not found for " p > "/dev/stderr"
    return p
  }	
}
function get_dev_mp(path,    mp,rp,count){
  #cmd="cat /proc/mounts | grep "$(realpath " dev ")""
  rp=realpath(path)
  cmd="cat /proc/mounts" # | grep "$(realpath '" rp "')""
  while ((cmd | getline )){
	#dev=$1 #don't need this yet
	print "cmd_out=" $0 > "/dev/stderr"
	mp=$2
	cmd2="echo " rp " | grep -c " mp 
	while ((cmd2 | getline )){
	    print "cmd2_out=" $0 > "/dev/stderr"
		count=$0
		break #this is uncessary
    }
    if ( count>0 ){
      return mp
      break
    }
  }
  if (count==0){
      print "Warning: dev not mounted! Inferring dev mount point from path" > "/dev/stderr"
	  mp=gensub(/^(.*[/]mnt[/][^/]*)[/].*/,"\\1",1,rp)
	  return mp
  }
}
Where is awk?

s243a
Posts: 2580
Joined: Tue 02 Sep 2014, 04:48
Contact:

Re: AWK: nested while loops w/ external commands

#10 Post by s243a »

phat7 wrote:
s243a wrote:Here is the awk code:

Code: Select all

function realpath(p){
  cmd="realpath '" p "'"
  while ((cmd | getline )){
	  rp=$0
	  break
  }
  if (length(rp)>0){
	return rp
  } else {
	print "Warning realpath not found for " p > "/dev/stderr"
    return p
  }	
}
function get_dev_mp(path,    mp,rp,count){
  #cmd="cat /proc/mounts | grep "$(realpath " dev ")""
  rp=realpath(path)
  cmd="cat /proc/mounts" # | grep "$(realpath '" rp "')""
  while ((cmd | getline )){
	#dev=$1 #don't need this yet
	print "cmd_out=" $0 > "/dev/stderr"
	mp=$2
	cmd2="echo " rp " | grep -c " mp 
	while ((cmd2 | getline )){
	    print "cmd2_out=" $0 > "/dev/stderr"
		count=$0
		break #this is uncessary
    }
    if ( count>0 ){
      return mp
      break
    }
  }
  if (count==0){
      print "Warning: dev not mounted! Inferring dev mount point from path" > "/dev/stderr"
	  mp=gensub(/^(.*[/]mnt[/][^/]*)[/].*/,"\\1",1,rp)
	  return mp
  }
}
Where is awk?
These are just the funtions in the awk file (i.e. sb_db_rec_field.awk). These functions are tested with the following code:

Code: Select all

SB_DB_REC_FIELD_AWK=./sb_db_rec_field.awk
  RECORD=\
'/mnt/_save+Tiny_Puduan+PreAlpha11+4+puppy_tascii+sfs__5e0ed puppy_tascii.sfs on /mnt/_save+Tiny_Puduan+PreAlpha11+4+puppy_tascii+sfs__5e0ed squashfs /initrd/mnt/dev_save/Tiny_Puduan/PreAlpha11.4/puppy_tascii.sfs'
  FILE_PATH="$(echo "$RECORD" | awk -v FIELD_NUM=6 -f "$SB_DB_REC_FIELD_AWK")"
  Mount_Point="$(echo "$RECORD" | awk -v FIELD_NUM=1 -f "$SB_DB_REC_FIELD_AWK")"
  PDRV_MNT="$(echo "$RECORD" | awk -v FIELD_NUM=7 -f "$SB_DB_REC_FIELD_AWK")"
  PDRV_UUID="$(echo "$RECORD" | awk -v FIELD_NUM=8 -f "$SB_DB_REC_FIELD_AWK")"
  echo "FILE_PATH=$FILE_PATH"
  echo "Mount_Point=$Mount_Point"
  echo "PDRV_MNT=$PDRV_MNT"
  echo "PDRV_UUID=$PDRV_UUID
/usr/local/psandbox/tests#L6

I didn't post this part because I didn't want to make the example too complicated. The idea is to try to infer a value if it is missing in the input file. I still have work to do on the part of the code that infers the uuid.
Find me on [url=https://www.minds.com/ns_tidder]minds[/url] and on [url=https://www.pearltrees.com/s243a/puppy-linux/id12399810]pearltrees[/url].

musher0
Posts: 14629
Joined: Mon 05 Jan 2009, 00:54
Location: Gatineau (Qc), Canada

#11 Post by musher0 »

@phat7:

Here! :lol:
Image
musher0
~~~~~~~~~~
"You want it darker? We kill the flame." (L. Cohen)

phat7
Posts: 179
Joined: Fri 05 Jun 2015, 08:54

#12 Post by phat7 »

musher0 wrote:@phat7:

Here! :lol:
Image
Not nested. Must be the wrong one.

musher0
Posts: 14629
Joined: Mon 05 Jan 2009, 00:54
Location: Gatineau (Qc), Canada

#13 Post by musher0 »

phat7 wrote:
musher0 wrote:@phat7:

Here! :lol:
Image
Not nested. Must be the wrong one.
;)
musher0
~~~~~~~~~~
"You want it darker? We kill the flame." (L. Cohen)

jamesbond
Posts: 3433
Joined: Mon 26 Feb 2007, 05:02
Location: The Blue Marble

#14 Post by jamesbond »

@s243a: after using getline, you may want to "close" it. Unless you plan never to read from the same file again (which is ok if the code only runs once).
Fatdog64 forum links: [url=http://murga-linux.com/puppy/viewtopic.php?t=117546]Latest version[/url] | [url=https://cutt.ly/ke8sn5H]Contributed packages[/url] | [url=https://cutt.ly/se8scrb]ISO builder[/url]

s243a
Posts: 2580
Joined: Tue 02 Sep 2014, 04:48
Contact:

#15 Post by s243a »

jamesbond wrote:@s243a: after using getline, you may want to "close" it. Unless you plan never to read from the same file again (which is ok if the code only runs once).
Yes, I fixed that in my psandbox project:

https://gitlab.com/s243a/psandbox/-/blo ... ox_fns.awk

Not properly closing files caused the function to ignore the first line of "cat /proc/mouts", the second time the function is called. This makes sense given how AWK is designed to loop through each line of a file.

Thanks for the warning though. The error had me stumped pretty good for a bit.
Find me on [url=https://www.minds.com/ns_tidder]minds[/url] and on [url=https://www.pearltrees.com/s243a/puppy-linux/id12399810]pearltrees[/url].

Post Reply