Unexpected Wrinkle Using Shell Script to Get Filenames

I’ve been using do shell script "ls -p " &… for a long time now, and finally noticed it doesn’t give the result expected when a filename includes a slash character.
If a folder contains for example, a file named “10/23/14 Goldfish1.jpg”, ls, in Terminal or AppleScript Editor, will return it as “10:23:14 Goldfish1.jpg”.

As far as Finder is concerned, that’s an illegal filename for a nonexistent file.
It’ll cause an error if you Tell the Finder to do something with it.

The quick and easy fix is to use sed to convert all those errant colons back into slashes.
Here’s the code:

-- BP 2014
-- ls sed Get names of files in folder
-- Fix filenames that include "/" 
-- ls converts / in filenames to :
-- A file named "10/23/14 Goldfish1.jpg" thus becomes "10:23:14 Goldfish1.jpg" which will choke the Finder
-- if you tell it to do something with the file.
-- Let's also use the ls -p flag to easily Filter folders from the directory listing

set fldrpath to (choose folder) as text
set fldrpath to (text 1 through ((length of fldrpath) - 1) of fldrpath) as text -- strip off the ending colon
set pospath to POSIX path of fldrpath -- convert to a UNIX friendly form
set pospath to quoted form of pospath

set namstr to do shell script "ls -p " & pospath -- get names of files in the folder The -p option flags folders by adding a trailing/

-- We have a string (namstr) with all the filenames in it, but Unix ls has helpfully replaced any '/'s in those file names with ':'s, which will choke the Finder, so I need to set the :'s back to /'s before continuing.
-- This is a job for sed.
-- sed pattern needs some nudging to make it through Applescript's parsing
-- This works in Terminal: x="AB:DEF:mugwart" | x=`echo $x | sed 's/:/\//g'` | echo $x 
----> AB/DEF/mugwart
-- Applescript shell script needs DOUBLE backslashses and quoted form to make it intact through the parser:
set SRpattern to quoted form of "s/:/\\//g" -- colon to slash -- Note Quoted form and DOUBLE backslash before the / character
set namstr to do shell script "echo " & quoted form of namstr & " | sed " & SRpattern
-- All the colons are now slashes again, and I can move on.

set oldtid to AppleScript's text item delimiters -- Convert the namstr text to a list
set AppleScript's text item delimiters to "\r"
set dirlst to every text item of namstr
set AppleScript's text item delimiters to oldtid

-- Folders, Apps and the like will appear in dirlst, but are easily filtered out when using ls -p  because they all end with "/"
-- Files without extensions, whose names end in a "/" will be filtered out too here.
--return dirlst

set filnamlst to {}
set directoryflag to "/" -- ls -p flags folders, Apps etc with this 
repeat with z in dirlst
	if the last text item of z is not directoryflag then set end of filnamlst to z as text
end repeat

-- Now the Finder won't choke when I tell it to do something with a file named "10:23:14 Goldfish1.jpg" or similar. 

return filnamlst

I never noticed this problem before because I almost never put slashes in filenames. It’s probably caused a few crashes for me, some people would likely be harder hit.

Using sed is probably a bit of overkill – tr will do what you want:

set namstr to do shell script "ls -p " & posPath & " | tr / :"

tr / : is a lot more readable than the sed string.

Thanks!

Mind you, for this job, sed could also filter out the slash-terminated folder names:

set pospath to POSIX path of (choose folder)
set filnamlst to paragraphs of (do shell script ("ls -p " & (quoted form of pospath) & " | sed -n '/\\/$/ !{ s/:/\\//g ; p ; }'"))

By using a different delimiter with sed’s ‘s’ function, you can avoid having to escape the replacement slash. For example, with bars: “sed ‘s|:|/|g’”. But since the address parameter here has to have slashes anyway, I’ve used slashes with ‘s’ too for consistency.

Well that certainly kills a few lines of code!
Three or four birds with one stone, not terribly readable, but it does kill one of those ugly and slow “repeat with x in y” loops.
Wonderful, thanks.

No worse than ASObjC. :wink:

Here’s the same code with added linefeeds, indents, comments, and backslash avoidance:

set pospath to POSIX path of (choose folder)
set filnamlst to paragraphs of ¬
	(do shell script ("
		# Get the names (one per line) of the items in the folder, with slashes appended to any folder or bundle names.
		ls -p " & (quoted form of pospath) & " |
		# Edit the lines, outputting only where specified.
		sed -n '
			/[/]$/ !{		# Where a line does not end with a slash .
				s|:|/|g ;	# . substitute slashes for colons .
				p ;		# . and output.
			}
		'
	"))

I’ll take verbose over cryptic any day :stuck_out_tongue:

Beauty is in the eye of the beholder. :smiley: