repair broken Finder aliases

Thanks but always no luck.

set brokenAliases to do shell script "/Users/admin/bin/AliasPath -bo"

set fileDescriptor to open for access ((path to desktop as text) & "FinderBrokenAliases.txt") with write permission
write brokenAliases to fileDescriptor
close access fileDescriptor

fails with the error :

error "2017-07-27 13:53:56.804 AliasPath[881:727082] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSURL initFileURLWithPath:]: nil string parameter'
*** First throw call stack:
(
	0   CoreFoundation                      0x00007fff837a057b __exceptionPreprocess + 171
	1   libobjc.A.dylib                     0x00007fff989f91da objc_exception_throw + 48
	2   CoreFoundation                      0x00007fff8381dc55 +[NSException raise:format:] + 197
	3   Foundation                          0x00007fff85158e8a -[NSURL(NSURL) initFileURLWithPath:] + 131
	4   Foundation                          0x00007fff85158df1 +[NSURL(NSURL) fileURLWithPath:] + 45
	5   AliasPath                           0x00000001089bd17e __main_block_invoke + 894
	6   AliasPath                           0x00000001089bc89c -[SpotlightSearch queryFinishedGathering:] + 1196
	7   CoreFoundation                      0x00007fff8372d54c __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
	8   CoreFoundation                      0x00007fff8372d44b _CFXRegistrationPost + 427
	9   CoreFoundation                      0x00007fff8372d1b2 ___CFXNotificationPost_block_invoke + 50
	10  CoreFoundation                      0x00007fff836eb782 -[_CFXNotificationRegistrar find:object:observer:enumerator:] + 2018
	11  CoreFoundation                      0x00007fff836ea76b _CFXNotificationPost + 667
	12  Foundation                          0x00007fff8512c677 -[NSNotificationCenter postNotificationName:object:userInfo:] + 66
	13  Foundation                          0x00007fff852b4022 -[NSMetadataQuery _noteNote4:] + 158
	14  CoreFoundation                      0x00007fff8372d54c __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
	15  CoreFoundation                      0x00007fff8372d44b _CFXRegistrationPost + 427
	16  CoreFoundation                      0x00007fff8372d1b2 ___CFXNotificationPost_block_invoke + 50
	17  CoreFoundation                      0x00007fff836eb782 -[_CFXNotificationRegistrar find:object:observer:enumerator:] + 2018
	18  CoreFoundation                      0x00007fff836ea76b _CFXNotificationPost + 667
	19  CoreFoundation                      0x00007fff837809f1 CFNotificationCenterPostNotificationWithOptions + 113
	20  Metadata                            0x00007fff84a8f5ad _postQueryNotification + 223
	21  Metadata                            0x00007fff84a5af77 ___pushNotification_block_invoke + 60
	22  CoreFoundation                      0x00007fff8373722c __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
	23  CoreFoundation                      0x00007fff837183c4 __CFRunLoopDoBlocks + 356
	24  CoreFoundation                      0x00007fff83717f06 __CFRunLoopRun + 1894
	25  CoreFoundation                      0x00007fff83717544 CFRunLoopRunSpecific + 420
	26  CoreFoundation                      0x00007fff83756d31 CFRunLoopRun + 97
	27  AliasPath                           0x00000001089bcdbc main + 700
	28  libdyld.dylib                       0x00007fff992da235 start + 1
	29  ???                                 0x0000000000000002 0x0 + 2
)
libc++abi.dylib: terminating with uncaught exception of type NSException" number 1006

If you need extraneous details, you may ask directly thru my personal mailbox.

On my side I have a version doing the job but using GUIscripting. With 432 path returned by mdfind the entire process took 347 seconds.


set startTime to current date

tell application "Finder"
	(*
	set theWindows to every window
	repeat with awindow in theWindows
		# Close every info window once so we will not have to do it in the handler
		if class of awindow is information window then close awindow
	end repeat
	*)
	close every window
end tell

set l to paragraphs of (do shell script "mdfind \"kMDItemKind == 'Alias'\"")

set y to ""
set n to ""
set pass to 0

repeat with e in l
	set pass to pass + 1
	set p to POSIX file e
	try
		tell application "Finder"
			try
				set a to p as alias
			on error
				# Retry after adding return at end of the path
				set e to e & return
				tell me to set p to POSIX file e
				set a to p as alias
			end try
			set theOriginal to my getOriginal(e) # here e is a POSIX path
			if original item of a exists then
				--set theOriginal to my getOriginal(e) # here e is a POSIX path
				set y to y & e & tab & theOriginal & linefeed # Add path2alias & path2original in y
			else
				--	set theOriginal to my getOriginal(e) # here e is a POSIX path
				set n to n & e & tab & theOriginal & linefeed # Add path2alias & path2original in n
				log "***try"
			end if
		end tell
	on error
		set n to n & e & tab & "***error" & linefeed # Here, I get that with aliases appearing as greyed in the Finder window
		--log "***error"
	end try
	--if pass = 50 then exit repeat # active only during tests
end repeat

# Save the list of broken aliases
set f to open for access (path to desktop as text) & "FinderBrokenAliasesXXX.txt" with write permission
write n as text to f
close access f

# Save the list of correct aliases
set f to open for access (path to desktop as text) & "FinderCorrectAliasesXXX.txt" with write permission
write y as text to f
close access f
set itsDuration to (current date) - startTime
tell application (path to frontmost application as string) to display dialog "It tooks : " & itsDuration & " seconds"

on getOriginal(brokenAliasPOSIXPath)
	set aFile to POSIX file brokenAliasPOSIXPath
	
	tell application "Finder"
		select aFile # open the window of the folder containing the alias
		
		set aFile to aFile as text
		
		repeat 10 times
			if ((get selection) as text) = aFile then exit repeat # Wait for the window containing the file
			delay 0.2
		end repeat
	end tell # Finder
	
	tell application "System Events" to tell process "Finder"
		set frontmost to true
		keystroke "i" using {command down} # Ask for Info window
		tell application "Finder"
			repeat 10 times # Wait for the new info window
				delay 0.2
				if (class of window 1) is information window then exit repeat
			end repeat
		end tell # Finder
		tell window 1
			--class of UI elements --> {scroll area, button, button, button, image, static text}
			tell scroll area 1
				--class of UI elements --> {image, static text, static text, static text, static text, scroll area, UI element, static text, static text, static text, static text, static text, static text, static text, static text, static text, static text, static text, static text, static text, static text, button, checkbox, UI element, static text, static text, UI element, static text, text field, checkbox, UI element, static text, UI element, static text, UI element, static text, static text, scroll area, button, button, menu button, checkbox}
				set theTexts to value of static texts
				repeat with i from 1 to count theTexts
					if theTexts's item i starts with "/" then
						set theOriginal to theTexts's item i
						log "got the original : " & theOriginal
						exit repeat
					end if
				end repeat
			end tell
			-- subrole of buttons --> {"AXCloseButton", "AXZoomButton", "AXMinimizeButton"}
			click button 1 # Close the Infos window
		end tell # window 1		
	end tell # System Events …
	
	tell application "Finder" to close window 1
	if i = (count theTexts) then set theOriginal to "** no original available **" # The window doesn't display an original, build a fake string
	
	return theOriginal --> "/Important/Téléchargements/ téléchargés pour Leopard/maj_Apple"
end getOriginal

#=====


This time I am satisfied because it no longer rely upon a localized string and it treat the “annoying” pathnames (using brute force).

Yvan KOENIG running Sierra 10.12.6 in French (VALLAURIS, France) jeudi 27 juillet 2017 13:58:44

I fixed the code to avoid the crash, same link.

THANKS.

This time IT WORKS - and it’s faster that my old fashioned one.

No problem with the non-ASCII chars used in the pathnames : {“é”, “…”, “ƒ”, “€”, “ê”, “◊”, “è”, “”, “à”, " ", “•”, “®”, “™”, “ç”}

Yvan KOENIG running Sierra 10.12.6 in French (VALLAURIS, France) jeudi 27 juillet 2017 14:39:52

Great, now this yields the same output as my script without two CR false positives.

Thanks, Stefan! Could you please upload your version to GitHub, possibly as a fork of the original?

Here is an enhanced version.

(* 
http://www.macscripter.net/post.php?tid=45852
*)

set brokenAliases to do shell script "/Users/admin/bin/AliasPath -bo"

# Replace the extraneous ending linefeed by the character "¶"
set brokenAliases to my remplace(brokenAliases, return & tab, "¶" & tab)

set fileDescriptor to open for access ((path to desktop as text) & "FinderBrokenAliases.txt") with write permission

# Write starting from 0 (delete possible old content)
set eof of fileDescriptor to 0
write brokenAliases to fileDescriptor
close access fileDescriptor


#=====
(*
replaces every occurences of d1 by d2 in the text t
*)
on remplace(t, d1, d2)
	local oTIDs, l
	set {oTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, d1}
	set l to text items of t
	set AppleScript's text item delimiters to d2
	set t to l as text
	set AppleScript's text item delimiters to oTIDs
	return t
end remplace

#=====

It replace in the flow of datas saved the “annoying” return characters by the character “¶”.
It contains an instruction forcing the script to drop the old content if the txt file exist when we start the script.

Yvan KOENIG running Sierra 10.12.6 in French (VALLAURIS, France) jeudi 27 juillet 2017 22:01:10

Actually return followed by tab never occurs

Alas, you are wrong.

Here are the annoying values with your script :

/Volumes/Macintosh HD/Users/Important/D80… alias	/Volumes/Western 2/D80…
/Volumes/Macintosh HD/Users/??????????/Library/Speech/Speakable Items/Application Speakable Items/AppleScript Editor/Target Application Alias
	/Applications/Utilities/AppleScript Editor.app
/Volumes/Macintosh HD/Users/??????????/Library/Speech/Speakable Items/Application Speakable Items/Pages/Target Application Alias
	/Applications/iWork '09/Pages.app
/Volumes/Macintosh HD/Users/??????????/Library/Speech/Speakable Items/Application Speakable Items/Numbers/Target Application Alias
	/Applications/iWork '09/Numbers.app
/Volumes/Macintosh HD/Users/??????????/Library/Application Support/PDF Nomad/URLBookmarks/D9B0C587-2F86-446B-952D-F2116A5B5DE7_bookmark.alias	/Users/??????????/Desktop/essai (Demo).pdf
/Users/??????????/Library/Speech/Speakable Items/Application Speakable Items/Numbers/Target Application Alias
	/Applications/iWork '09/Numbers.app

And here are the lines returned by the completed script.

/Volumes/Macintosh HD/Users/Important/D80… alias	/Volumes/Western 2/D80…
/Volumes/Macintosh HD/Users/??????????/Library/Speech/Speakable Items/Application Speakable Items/AppleScript Editor/Target Application Alias¶	/Applications/Utilities/AppleScript Editor.app
/Volumes/Macintosh HD/Users/??????????/Library/Speech/Speakable Items/Application Speakable Items/Pages/Target Application Alias¶	/Applications/iWork '09/Pages.app
/Volumes/Macintosh HD/Users/??????????/Library/Speech/Speakable Items/Application Speakable Items/Numbers/Target Application Alias¶	/Applications/iWork '09/Numbers.app
/Volumes/Macintosh HD/Users/??????????/Library/Application Support/PDF Nomad/URLBookmarks/D9B0C587-2F86-446B-952D-F2116A5B5DE7_bookmark.alias	/Users/??????????/Desktop/essai (Demo).pdf
/Users/??????????/Library/Speech/Speakable Items/Application Speakable Items/Numbers/Target Application Alias¶	/Applications/iWork '09/Numbers.app

In fact there were six broken alias with the ending returns but I zipped 2 of them to try to see if they are really useful at this time.
It seems that they aren’t useful but I play safe.

I turn the occasion to account that I missed something in a Shane’s proposal.
He carefully added some words at the mdfind instruction.
His version was :

set allAliasFiles to (do shell script "mdfind \"kMDItemKind == 'Alias'\"" without altering line endings)

Thanks to “without altering line endings” the ending return characters were no longer dropped.

Yvan KOENIG running Sierra 10.12.6 in French (VALLAURIS, France) vendredi 28 juillet 2017 10:20:02

What script do you mean? When posting the latest version of the CLI I didn’t post a script and the CLI itself definitely does not create return & tab sequences with -bo.

I wrote about :

(* http://www.macscripter.net/post.php?tid=45852 *)
# Use the AliasPath 1.1 CLI from :http://klieme.com/Downloads/misc/AliasPath1.1.zip, http://www.macscripter.net/viewtopic.php?id=45852&p=2

set brokenAliases to do shell script "/Users/admin/bin/AliasPath -bo"

# Replace the extraneous ending linefeed by the character "¶"
set brokenAliases to my remplace(brokenAliases, return & tab, "¶" & tab)

set fileDescriptor to open for access ((path to desktop as text) & "FinderBrokenAliases.txt") with write permission

# Write starting from 0 (delete possible old content)
set eof of fileDescriptor to 0 # ADDED
write brokenAliases to fileDescriptor
close access fileDescriptor


#=====
(*
replaces every occurences of d1 by d2 in the text t
*)
on remplace(t, d1, d2)
	local oTIDs, l
	set {oTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, d1}
	set l to text items of t
	set AppleScript's text item delimiters to d2
	set t to l as text
	set AppleScript's text item delimiters to oTIDs
	return t
end remplace

If I disable the instruction : set brokenAliases to my remplace(brokenAliases, return & tab, “¶” & tab) I get the first group of datas posted in my late message.
If I enable it, I get the second group of datas.

Guess why there are some ¶ characters in the second group.

Your CLI doesn’t explicitly create such datas.
It’s just that when it get the path
"/Volumes/Macintosh HD/Users/???/Library/Speech/Speakable Items/Application Speakable Items/Pages/Target Application Alias
" (Yes, with a return character at end),
it add a tab and “/Applications/Utilities/AppleScript Editor.app”

I don’t understand why you are surprised. You edited the code of the CLI to achieve that, no less, no more.

If I run the beginning of the “old” script :

set allAliasFiles to (do shell script "mdfind \"kMDItemKind == 'Alias'\"" without altering line endings)

set {TID, text item delimiters} to {text item delimiters, linefeed}
set allAliasFiles to text items of allAliasFiles
set text item delimiters to TID
allAliasFiles

I get :

{"/Users/??????????/Library/Speech/Speakable Items/Application Speakable Items/System Preferences/Target Application Alias
", "/Users/??????????/Library/Speech/Speakable Items/Application Speakable Items/VLC/Target Application Alias
", "/Users/??????????/Library/Speech/Speakable Items/Application Speakable Items/Xcode/Target Application Alias
", "/Users/??????????/Library/Speech/Speakable Items/Application Speakable Items/iTunes/Target Application Alias
", "/Users/??????????/Library/Speech/Speakable Items/Application Speakable Items/HexEdit/Target Application Alias
", "/Users/??????????/Library/Speech/Speakable Items/Application Speakable Items/Finder/Target Application Alias
", "/Users/??????????/Library/Speech/Speakable Items/Application Speakable Items/ImageWell/Target Application Alias
", "/Users/??????????/Library/Speech/Speakable Items/Application Speakable Items/JavaApplicationStub/Target Application Alias
", "/Users/??????????/Library/Speech/Speakable Items/Application Speakable Items/Mail/Target Application Alias
", "/Users/??????????/Library/Speech/Speakable Items/Application Speakable Items/Safari/Target Application Alias
", "/Library/Fonts/Monospaced ƒ/Andale Mono.ttf", … 

Which show the aliases safe ones as well as broken ones with their ending return.

I rebuilt the script using your first version of the CLI :

set allAliasFiles to (do shell script "mdfind \"kMDItemKind == 'Alias'\"" without altering line endings)
set {TID, text item delimiters} to {text item delimiters, return}
set allAliasFiles to text items of allAliasFiles
set text item delimiters to TID
repeat with i from 1 to count allAliasFiles
	set item i of allAliasFiles to quoted form of item i of allAliasFiles
end repeat
tell AppleScript
	set oldTIDs to text item delimiters
	set text item delimiters to space
	set bashList to allAliasFiles as string
	set text item delimiters to oldTIDs
end tell


tell application "System Events"
	set maybe to exists file "/Users/admin/bin/AliasPath0"
	log maybe
end tell
set brokenAliases to do shell script "/Users/admin/bin/AliasPath0 -b " & bashList
set fileDescriptor to open for access ((path to desktop as text) & "FinderBrokenAliasesCli0.txt") with write permission
set eof of fileDescriptor to 0
write brokenAliases to fileDescriptor
close access fileDescriptor

As you see, the original version of the CLI is named AliasPath0 here so that I may have two versions available for tests.
Alas, this version returns an empty text file.

Yvan KOENIG running Sierra 10.12.6 in French (VALLAURIS, France) vendredi 28 juillet 2017 12:11:17

Yvan, I was surprised because I didn’t get where those new line characters came from but now I understand.

It’s not a common problem, the problem is related to aliases you’ve created. Some of them seem to have trailing new line characters. That’s not the default behavior when creating an alias, you must have added them - maybe accidentally.

It might be more suitable to remove the affected trailing new line characters from the alias files manually.

No, I didn’t created these aliases explicitly. If I did, msh wouldn’t have the same items.

The folder Speech is not created by default but is installed by request when we need the speech tools. The folder doesn’t exist on my grand-son MacBook Pro, no more on my grand-daughter’s one.

I guess that they the entire folder is created when we ask the system to use Speech components.

I will certainly not change the names of these aliases. If they are useful, changing the names would push the applications trying to use them to crash.

Searching in Google, I retrieved a support page :https://support.apple.com/kb/PH14230?locale=en_US in which I read :
Choose Apple menu > System Preferences, click Dictation & Speech
There is no such item in 10.12.6 (or at least my old eyes don’t see it).

Amusing detail: when I retrieved the ‘annoying’ aliases with Spotlight, in the window displaying them, the ASCCI part of the names was moved vertically due to the ending return. If I copy these names and paste them as I did here, we may see that there is really an ending linebreak

Target Application Alias

Target Application Alias

Target Application Alias

Target Application Alias

Target Application Alias

Target Application Alias

Target Application Alias

Target Application Alias

Target Application Alias

Target Application Alias

Target Application Alias

Target Application Alias

Target Application Alias

Target Application Alias

Target Application Alias

Target Application Alias

Target Application Alias

Target Application Alias

Target Application Alias

Target Application Alias

Target Application Alias

Target Application Alias

Target Application Alias

Target Application Alias

When I navigate to open the folder containing these aliases, the names are displayed with a question mark replacing the return. I select a file name and copy it, I really get a question mark :

Target Application Alias?

Which may explain why most of us don’t take care of them (adding that normally the user’s library is hidden)

Yvan KOENIG running Sierra 10.12.6 in French (VALLAURIS, France) vendredi 28 juillet 2017 14:02:57

FWIW, on my Mac all those aliases and other files have a creation date January 18, 2014, which is back in the 10.9 time-frame. Some of the apps referred to are long gone, too.

And when I look at the code in some of the scripts – which are old resource-fork versions without extensions and thus open as untitled – they look like dinosaurs, too. I see stuff like using “set theStyledTextRecord to (theText as record)/set theText to «class ktxt» of theStyledTextRecord” before using strings in dialogs. It’s really quite nostalgic :wink:

So I do wonder if they’re doing anything more than taking up space these days…

Thank you for your feedback Shane.

According to it, I zipped all these files.
If before 2017/12/31 (guess why) no failure strike, I will remove the zipped files with the folders which contain each of them but I’m not sure if I may delete more.
At first thought, it may be done as there is no such folder on my grand-son and grand-daughter macBooks.

Courage, I will now zip the Speech folder itself :wink:

It’s probably not a problem. I wasn’t asked for a password for the zip process and for the removal of the original.

Yvan KOENIG running Sierra 10.12.6 in French (VALLAURIS, France) vendredi 28 juillet 2017 16:26:48

Mine date back to 2006. Time to make a clean install? :smiley:

You can read more about without altering line endings in TN2065.

It’s a shame that the source for AliasPath is not being shared.

Thanks.

(1) I’m aware of “without line endings” but as I rarely use shell commands, I forgot it and worse I missed it in Shane’s proposal.

(2) The source of the original AliasShare is shared.
StefanK is free to choose if he wish to share its changes or if he doesn’t.

(3) I compiled the original source with Xcode and tried to use it with :

set allAliasFiles to (do shell script "mdfind \"kMDItemKind == 'Alias'\"" without altering line endings)

set {TID, text item delimiters} to {text item delimiters, linefeed}
set allAliasFiles to text items of allAliasFiles
set text item delimiters to TID
allAliasFiles

repeat with i from 1 to count allAliasFiles
	set item i of allAliasFiles to quoted form of item i of allAliasFiles
end repeat

set {TID, text item delimiters} to {text item delimiters, linefeed}
set text item delimiters to space
set allAliasFiles to allAliasFiles as text
set text item delimiters to TID

set pathToCLI to POSIX path of ((path to desktop as text) & "aliasPath") # EDIT to fit your needs
tell application "System Events"
	set maybe to exists file pathToCLI
end tell


set brokenAliases to do shell script pathToCLI & space & allAliasFiles


# Replace the extraneous ending linefeed by the character "¶"
set brokenAliases to my remplace(brokenAliases, return & ": ", "¶: ")

# If you prefer you may replace the colon + space separator by tab character
set brokenAliases to my remplace(brokenAliases, ": ", tab)

set fileDescriptor to open for access ((path to desktop as text) & "FinderBrokenAliases?.txt") with write permission
set eof of fileDescriptor to 0
write brokenAliases to fileDescriptor
close access fileDescriptor

#=====
(*
replaces every occurences of d1 by d2 in the text t
*)
on remplace(t, d1, d2)
	local oTIDs, l
	set {oTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, d1}
	set l to text items of t
	set AppleScript's text item delimiters to d2
	set t to l as text
	set AppleScript's text item delimiters to oTIDs
	return t
end remplace

#=====

The process behaved flawlessly.

Yvan KOENIG running Sierra 10.12.6 in French (VALLAURIS, France) samedi 29 juillet 2017 10:45:44

I beg your pardon :confused:


@Yvan, I added a new switch -t to AliasPath.

By default (without passing the switch) the alias paths are trimmed by leading and trailing new line and white space characters.
If you pass it, the paths are printed unchanged.

New Build: AliasPath1.2

Thank you Stefan.

Yvan KOENIG running Sierra 10.12.6 in French (VALLAURIS, France) samedi 29 juillet 2017 12:23:18

Really??? It’s just funny — and a modified binary should include the license of the original.

Meanwhile my version can be treated as refactored rather than modified :wink:

It’s not a secret and it’s written in either (Objective-)C or Swift which has no purpose on MS here. StefanK just wrote a binary so you can use it. You want the code? Here is one of the thousand examples on how to resolve alias paths.