Match printer URI from ippfind with a printer listed in lpstat -p?

The ippfind command lists all currently available IP printers, and outputs a list of their URIs.

Is there a way to determine which URI in the ippfind list matches a printer listed and described by lpstat -l -p? The printer descriptions given by lpstat -l -p do not include the URI shown by ippfind and I can’t figure out how to match one output to the other.

@Fredrik71 I am not setting up a printer; I am trying to find a way to match the list of printers that are already set up, and have different descriptions in lpstat and ippfind. And I am trying to do this for a utility that other people can use, so I can’t change anything in their systems.

But, as always, thank you for taking the trouble to make a suggestion.

@Fredrik71 - on every system I try, the description from lpstat does NOT match the descriptions from ippfind. I am trying to find a way to do this:

  1. run ippfind and get the list of descriptions

  2. run lpstat and get the list of descriptions. This list will be different from the ippfind list.

  3. figure out which printer in the ippfind list matches which printer in the lpstat list.

If you have tried this and have an answer, I would be very grateful.

@Fredrik71 - No. The URL in lpstat is different from the URI in ippfind. If they had been the same, I would never have asked this question. But thank you again for taking the trouble to make a guess about what the answer might be.

Here is the output for one of my printers from ippfind (which only dispays printers that are online and have IP addresses):

ipp://LJ-P3015-Edward.local:631/LJ-P3015-Edward

And here is the corresponding printer description from lpstat -l -p:

printer HP_LaserJet_P3010_Series is idle.  enabled since Fri Dec 22 12:54:57 2023
	Form mounted:
	Content types: any
	Printer types: unknown
	Description: Edward LaserJet P3015
	Alerts: none
	Location: 
	Connection: direct
	Interface: /private/etc/cups/ppd/HP_LaserJet_P3010_Series.ppd
	On fault: no alert
	After fault: continue
	Users allowed:
		(all)
	Forms allowed:
		(none)
	Banner required
	Charset sets:
		(none)
	Default pitch:
	Default page size:
	Default port settings:

I can use StefanK’s Bonjour Events to give me information that makes it possible to see that these two are the same printer, but I am looking for a way to do this without using a separate application. There are some strings in common between the two outputs, but I need a way to be sure that I am matching two printers exactly.

Are there any other command options for lpstat that you can add so it will return url?

@robertfern - None that I’ve ever found. lpstat -v [printername] gives this result:

device for Edward_LaserJet_P3015: dnssd://HP%20LaserJet%20P3010%20Series%20%5B13EF70%5D._printer._tcp.local./BINPS

As you see, this is not the same as the ipp:// address returned by ippfind. Again, third-party utilities like Bonjour Browser can provide information that makes it possible to match the two entries, but I’m looking for something that AppleScript or a shell script can provide.

What does -H get you?

@robertfern - -H gives /private/var/run/cupsd for every printer on my system.

@Fredrik71 - As I said in earlier posts, I am trying to write a utility that will work on other people’s systems. I can’t rename their printers for them. I have to work with the system as it exists. Thank you again for your suggestions, but please understand that I can NOT change other people’s system when they run the utility that I am trying to write.

Just a shot in the dark here.

set lpd to "Edward LaserJet P3015"
set ipp to "LJ-P3015-Edward"

set AppleScript's text item delimiters to space
set lName to text items of lpd
set parseDesc to {"LJ", item 3 of lName, item 1 of lName}
--> {"LJ", "P3015", "Edward"}

set AppleScript's text item delimiters to "-"
parseDesc as text
--> "LJ-P3015-Edward"

We only have a single example to work with but it looks like the direct correlation you seek does not exist. When people set up printers and stuff, they may not pay much attention to consistency across platforms.

However, the two printer ‘names’ do contain basically the same information: make of printer, model of printer, general local name of printer. However, that information isn’t formatted consistently.

Maybe you can check several printers and see if they format their name/description the same way. If so, you can parse that and match them up. If every printer is named randomly, then perhaps you’re SOL.


As an aside, what is returned with lpstat -t

The -t option returns the broadest range of information about the device.

@Mockman - Thank you for that code. I had thought of trying something like this, but unfortunately the Bonjour Service Name (in this case HP LaserJet P3010 Series [13EF70]) does not need to match anything in the Host Name (in this case LJ-P3015-Edward) or the macOS description (in this case Edward LaserJet P3015). Mine happen to have some things in common, but if I had two printers with the same model number (P3015dn), I could not use this to tell which is which.

@Fredrik71 - the output of the command you mentioned does not produce anything matches anything in the output of lpstat -l -p.

@Fredrik71 and @Mockman - Here is a script I wrote that performs this task, but it uses an old version of StefanK’s Bonjour Events utility to match the output from ippfind and lpfind -l -p. The question in this thread is: how can I do the same thing without a separate utility:

-- Display a list of available networked IP printers
-- by Edward Mendelson, using code adapted from many posts at MacScripter.net
-- requires "Bonjour Events" by Stefan Klieme, downloadable here:
-- http://www.klieme.ch/pub/Bonjour%20Events.zip

set noPrinters to 0
try
	set printerNames to (do shell script "lpstat  -l -p | grep -i Description: |awk -F'Description: ' '{print $2}' ") -- as list
on error
	set noPrinters to 1
end try
if printerNames = "" then
	set noPrinters to 1
end if
if noPrinters is 0 then
	try
		set queueNames to (do shell script "lpstat -a | awk -F' accepting' '{print $1}'") -- as list
	on error
		set noPrinters to 1
	end try
end if

if noPrinters = 0 then
	try
		set printerList to (every paragraph of printerNames) as list
		set queueList to (every paragraph of queueNames) as list
	end try
	
	set item_num to 0
	set ipPrinterList to {}
	repeat with j in printerList
		
		set thePrinter to j
		set item_num to item_num + 1
		set theQueue to (item item_num in queueList)
		
		set dnsURL to do shell script "lpstat -v " & theQueue
		set dnsString to (do shell script "perl -e 'use URI::Escape; print uri_unescape(\"" & dnsURL & "\")';")
		
		try
			tell application "Bonjour Events"
				scan type "_ipp._tcp" in domain "local"
				repeat until browser finished
					delay 0.5
				end repeat
				
				if (count services) > 0 then
					set nameList to name of services
					set addressList to IPv4 address of services
				else
					set nameList to {}
					set addressList to {}
				end if
				quit
				-- Bonjour Events quits automatically after 2 minutes of inactivity
			end tell
		on error errorMessage number errorNumber
			display dialog "An error occurred: " & errorMessage & " (" & errorNumber & ")"
		end try
		
		set ipPrinterFound to false
		repeat with currentItem in nameList
			if currentItem is in dnsString then
				set ipPrinterFound to true
				set currentListItem to currentItem as item
				set dnsNumber to my list_position(currentListItem, nameList)
				set printerIP to item dnsNumber in addressList
				copy thePrinter to the end of ipPrinterList
				-- tell me to activate
				-- display dialog thePrinter & return & return & "has the DNS instance name" & return & return & currentItem & return & return & "IP address:" & space & printerIP & return & return & "queue name:" & space & theQueue buttons {"OK"}
				exit repeat
			end if
		end repeat
		
	end repeat
	
	tell me to activate
	set chosenPrinter to choose from list ipPrinterList
	set chosenPrinter to item 1 of chosenPrinter
	set printer_num to my list_position(chosenPrinter, printerList)
	set theQueue to (item printer_num in queueList)
	display dialog "You chose:" & return & return & (chosenPrinter as string) & return & return & "queue name:" & return & return & (theQueue as string) buttons {"OK"}
	error number -128
	
else
	tell me to activate
	display dialog "No printers found!" buttons {"OK"}
	error number -128
	
end if

on list_position(this_item, this_list)
	repeat with i from 1 to the count of this_list
		if item i of this_list is this_item then return i
	end repeat
	return 0
end list_position

@Fredrik71 - The reason is that I need the description of the printer (the “friendly name”) in order to let the user choose an available printer from a list. The names reported by ippfind can be completely different from the printer names shown in macOS dialogs, and the user may not recognize those names.

The script that I posted earlier displays a list of friendly names. That is what I am trying to do without using the Bonjour Events app.

@Fredrik71 - As you can see from the posts above, on my system, all three networked printers have different descriptions in ippfind and lpstat. I can assure you that I began by trying to use your method, and it absolutely does not work on my system. Thank you again for all your guesses.

@Fredrik71 - the contents of /Library/Preferences/org.cups.printers.plist are the same as lpstat -l -p. That file does not contain the ipp:// address reported by ippfind.

@Fredrik71 - Yes, I already know exactly what you reported and I have read the documents thoroughly. They do not provide the answer to the question: how to match a printer with a dnssd:// or ipp:// path to the information given for that printer in lpstat, without using a third-party utility like Bonjour Events.

If you find the exact answer to that question, of course I will be grateful. But please do not spend any more of your time researching possible solutions that have not actually been tested and shown to work.

@Fredrik71 - Unfortunately, this is not correct if you have installed printers that are offline because (for example) they are on your office network and you are at home. My lpstat list contains seven printers. My ippfind list contains three printers. The problem I am trying to solve is how to tell which of the lpfind printers are available by matching them to the ippfind list.

Your script produces this error on my system:

error "*** -[NSDictionary initWithObjects:forKeys:]: count of objects (3) differs from count of keys (0)" number -10000

I should have spelled this out in an earlier message so that I could save you a lot of time testing something that would not work.

@Fredrik71 - Thank you again. I already know about dns-sd, but it doesn’t provide any information that isn’t provided by ippfind. I have explored all the options of dns-sd with no success.

OK

Here goes.
I found some option switches for the 2 commands that both will return the Printer URI so you can match them up.

"ippfind -l -s "
“lpstat -l -p -v”

ippfind will have the ip address of the printers in the URI.
lpstat will have the dns address of the printers in the URI.

Now you just have to convert the dns address to IP address and match them up

@robertfern - This looks very promising, but under Sonoma ippfind -l -s -v produces this error message ippfind: Unknown option “-v”. What version are you using?

Also, I don’t see the dns address in the output from lpstat -l -p. Could you post an example?

I’m using Monterey.

Also I found a command that will convert domain name to ip.
“arp < domain name >”
my printer uri came up as ipp://NPI0458AF.local:631/ipp/print
so the command is “arp NPI0458AF.local”

** Edit ** OOPS, the -v goes on the lpstat command. my bad. I fixed the post above.