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 - 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.
@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.
@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.
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.
@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?
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.