Apple Event: May 7th at 7 am PT

Looks like no one’s replied in a while. To start the conversation again, simply ask a new question.

Applescript to read a text file and move files to new location

Hi,


I have around 4000 files that have been supplied in a complication folder structure - I need them in a more human readable structure. Supplied with the files is an Excel spreadsheet that among other things lists the files current location, and the desired location like this:


filepath filename newlocation

\1\00\02\0002c5d0-185e-4404-8837-eb50e89cd52c\ file1.zip Newfolder/zips/

\1\00\0f\000f17bc-3bdb-4d91-a573-3c6af92a1caa\ file32.tif Newfolder/Images/Tiffs/

...

...



Is it possible to run an applescript to pick up the file from the existing location and move it to the newlocation, assuming I saved the excel file as a csv or plain text file?


I hope someone can help! 😎

Posted on Mar 5, 2018 7:07 AM

Reply

Similar questions

31 replies

Mar 7, 2018 1:11 AM in response to rccharles

Hello everyone. Firstly thanks for your input so far!


To clarify, the long strings like: \1\00\02\0002c5d0-185e-4404-8837-eb50e89cd52c\


are actual file paths exported from a database to an excel file. I also have a disk containing all the exported files, in a similar folder structure.


I don't think that's a problem as I can simply search and replace all the backslashes in the excel file with forward slashes.


User uploaded file

Mar 7, 2018 4:03 AM in response to VikingOSX

Hi,


Here is a screenshot of the actual folder structure on the supplied disk, identifying a file in this location: 1/2a/2a0b49a9-8ec6-4567-b952-50386f74d3cd/source/

User uploaded file


and here is a screenshot of the corresponding excel file, first column showing 1. Current location 2. Filename 3. Desired location.


User uploaded file

(in text for clarity)

\1\2a\0b\2a0b49a9-8ec6-4567-b952-50386f74d3cd\ SOTG_XMAS17_GB_Strut card A5.zip /PROMOTIONS/SEASONAL/2017/Autumn



I can certainly process the excel file to convert the back slashes and create a clean text file with just these 3 fields.


The actual desired folder structure I have already created by extracting that column as a text file and running this terminal command: xargs -tI % mkdir -p % < folders.txt


I don't know where to start with applescript though -


take the cleaned up text file,


navigate to the folder path (column 1)


select the file (column 2)


Move the file to new folder path (column 3)

Mar 8, 2018 9:11 AM in response to Phillip Briggs

Phil,


I have had mixed success this morning. I can successfully read the elements from a CSV, construct the source and destination paths, and copy to a new folder hierarchy correctly. On a mounted USB stick.


For some reason, when I have the same source structure on my mounted Synology NAS mount point, the copy process is blocked due to permissions (even with administrator privileges). In the Terminal, I can see that the destination folder structure is created on the NAS, but it does not appear in the Finder view of the mount point — even after unmounting and remounting it. Chflags hidden is off. Can't explain it after fighting this issue all morning.


Here is the CSV that I tested, and how the input and output on the USB stick appears:

User uploaded file

User uploaded fileUser uploaded file


And here is the AppleScript:

-- read a csv into a list of rows. Loop through the rows to concatenate first two

-- fields, and then hopefully copy the file to new destination hierarchy built from the

-- third CSV field.


property server_path : "/Volumes/Online_DAM/"

property new_path : server_path & "NewFS/"

-- property server_path : "/Volumes/A_Utility/ASTest"

-- property new_path : "/Volumes/A_Utility/VikingPath/"

property delim : ","

property isDesktop : (path to desktop as text) as alias

property csv : {"public.comma-separated-values-text", "public.delimited-values-text"}


set msg to "Choose the input CSV file:"

set rowItems to {}


-- prompt for CSV file and read its contents by row into a list

set csvfile to (choose filewith promptmsgof typecsvdefault locationisDesktop without invisibles, multiple selections allowed and showing package contents)

set csvdata to (read csvfile as «class utf8» using delimiter linefeed) as list


repeat with aRow in csvdata

-- get a list of this CSV row items split on delimiter

set rowItems to my parseCSV(aRow, delim)


-- sPath becomes the source path and filename

set sPath to server_path & first item of rowItems & middle item of rowItems


-- make any uppercase words into titlecase in destination path

set x to do shell script "ruby -e 'puts ARGV.first.gsub(/\\w+/, &:capitalize);' " & last item of rowItems


-- nPath becomes the new_path and appended destination folder

set nPath to new_path & x


-- make the folder path hierarchy if it doesn't exist, otherwise do nothing

do shell script "mkdir -p " & nPathpassword "xxxxxx" with administrator privileges


try

-- ditto will copy all existing file attributes to the destination

do shell script "ditto " & sPath & space & nPathpassword "xxxxxx" with administrator privileges

on error errmsg number errnbr

my error_handler(errnbr, errmsg)

return

end try

end repeat

return


on parseCSV(rowText, adelim)

-- split the supplied CSV row on its delimiters. Return quoted list elements.

set {TID, AppleScript'stext item delimiters} to {AppleScript'stext item delimiters, adelim}

set rowItems to text items of rowText

set AppleScript'stext item delimiters to TID

return rowItems as list

end parseCSV


on error_handler(nbr, msg)

return display alert "[ " & nbr & " ] " & msg as critical giving up after 10

end error_handler

Mar 9, 2018 6:18 AM in response to Phillip Briggs

I have solved the white-space file issue. One line of code fix.



-- ditto will copy all existing file attributes to the destination


do shell script "ditto " & sPath's quoted form & space & nPathpassword "xxxxxx" with administrator privileges


This line will move files instead of copy. I have tested it, with same results as ditto:

do shell script "mv " & sPath'squoted form & space & nPathpassword "xxxxxx" with administrator privileges


The Finder does not like POSIX paths which are what you are using in the CSV, and I am building in the script from CSV components. Would advise staying with the UNIX move (mv) command.


CSV

User uploaded file

User uploaded fileUser uploaded file

Mar 7, 2018 5:04 AM in response to Phillip Briggs

Will filepath, filename, and newlocation be the actual CSV header names, or do you plan to omit the header row in the CSV?


I see two destination path examples in your spreadsheet:

  1. Newfolder/....
  2. PROMOTIONS/...


What will the organizing, containment folder be for the above?

  1. Desktop
  2. Documents
  3. Folly
    1. Folly/Newfolder/...
    2. Folly/PROMOTIONS/...

Mar 6, 2018 12:55 PM in response to Phillip Briggs

That's what we want around here. We will help you learn.


Here is a script for reading and parsing a cvs file.

There are a bunch of junk characters in the comments 😟.


https://macscripter.net/viewtopic.php?id=44517


You can move the files with either unix or finder.


Since the path is in unix format you would use the

mkdir -p

get the directory path so you can use the mkdir command

dirname

https://www.cyberciti.biz/faq/unix-get-directory-name-from-path-command/

mv -i inputname outputnname

is the move command.


Author: rccharles

It is easier to diagnose problems with debug information. I suggest adding log statements to your script to see what is going on. Here is an example.


For testing, run in the Script Editor.

1) Click on the Event Log tab to see the output from the log statement

2) Click on Run



-- ---------------------------------------------------------------
on processFile(theAlias, theOutputFolder)
    set inString to theAlias as string
    log "  inString = " & inString
   
    set unixInputFile to POSIX path of inString
    log "  unixInputFile = " & unixInputFile
   
    set quotedUnixInputFile to quoted form of unixInputFile
    log "  quoted form is " & quotedUnixInputFile
    set toUnix to "/usr/local/bin/exiftool -GPSLatitude -GPSLongitude " & quotedUnixInputFile
    log "  toUnix is " & toUnix
   
    try
        set seeUnix to do shell script toUnix
        log "  seeUnix is " & seeUnix
        if seeUnix is not "" then
            set fileTarget to theAlias as text
            if fileExists(fileTarget) then
                log "the filename already exists.  It may or may not be the same file."
            else
                try
                    tell application "Finder"
                        copy file theAlias to folder theOutputFolder
                    end tell
                on error errMsg
                    log "copy file got an error. Error message was " & errMsg
                    return
                end try
            end if
           
           
        end if
        return
    on error errMsg
        log "unix exiftool got an error. Error message was " & errMsg
        return
    end try
   
end processFile

Mar 6, 2018 2:25 PM in response to Phillip Briggs

Is it possible to run an applescript to pick up the file from the existing location and move it to the newlocation, assuming I saved the excel file as a csv or plain text file?


I doubt it. Those null-byte directory names in your example will be an obstacle to process on a "UNIX" machine as the presence of a null byte, whether in a file or directory name signals all UNIX commands, or scripting languages to halt when attempting to process the string representing the file or directory name. Thus, one cannot descend into that directory structure to pluck out the filenames.


If the filenames were in a compliant named macOS directory hierarchy, then it would be a simple matter to descend into that structure, access, and copy/move the filename into the destination directory structure.

Mar 6, 2018 7:32 PM in response to VikingOSX

I didn't notice the backslash until my second post. I figured the backslash was the windows file separator instead of the unix file separator. Anyway, the original poster needs to clarify. Can you have a 0x00 in a file name?


So what is this?

\1\00\02\0002c5d0-185e-4404-8837-eb50e89cd52c\

I didn't think the backslash was used to specify binary?

$ echo $((0xbc))

grep "["$'\xe0\xa4\x85'"-"$'\xe0\xa4\xb5'"]"

echo -e -n "\033\07\017">tf

but this requires echo -e

shell - echo bytes to a file - Unix & Linux Stack Exchange

looking around the web, didn't see a good example of how to write strings in hex 😕
.

R

Mar 7, 2018 3:34 AM in response to Phillip Briggs

Phillip,


The file structure that you show above (2018-03-07) in the screen capture won't be an issue. Again, you make reference to a disk with the actual Excel spreadsheet paths on it.


Can you do a screenshot of the expanded directory hierarchy on your disk that corresponds to the spreadsheet entry for \1\00\... ? If it was written to disk in a normal UNIX naming convention (e.g. /1/00/...) — also shown by your above screenshot, then there is no nul-byte issue, and the directory hierarchy can be walked to copy/move the files that you designate.


Also, is it your goal to only affect the files shown in the spreadsheet (which would require the proper change of '\' to '/' in their paths), and dynamically create the output folder hierarchy (e.g. Newfolder/Images/jpg) as files other than .zip or .tif are encountered?

Mar 7, 2018 4:34 AM in response to Phillip Briggs

Ok. No nul issue in the filesystem.


Presumably, you want a prompt asking for the parent folder to contain your third column directory structure? Must the folder names be in uppercase? Why not titlecase (e.g. /Promotions/Seasonal/2017/Autumn)?


Is the CSV with, or without headers?


Extra care will need to be taken programmatically to address white-space in file and folder names.

Mar 7, 2018 5:16 AM in response to VikingOSX

Hi,


I'd omit the header row.


the first destination path was just an example - the latest example were from actual data.


The actual folder structure wil be from this:


/Volumes/Online_DAM/1/


(e.g. 1/00\02\0002c5d0-185e-4404-8837-eb50e89cd52c/source/SOTG_XMAS17_GB_Strut card A5.zip


to this:


/Volumes/Online_DAM/NewFS/


(e.g

/Volumes/Online_DAM/NewFS/Promotions/Seasonal/2017/Autumn/SOTG_XMAS17_GB_Strut card A5.zip )

note that each file is always in a folder: "Source" which will not be replicated in the new structure.

Mar 7, 2018 6:23 AM in response to Phillip Briggs

I have most of the AppleScript fleshed out including the part where I convert the all-caps destination path into titlecase (one line of code).


I observed that your source location is named:


/Volumes/Online_DAM/1/


and your example file path entry in the CSV is:

1/00/...


Does this imply that the joined path is:


/Volumes/Online_DAM/1/1/00....


or should the source location be:


/Volumes/Online_DAM/


so that the combined source path is:


/Volumes/Online_DAM/1/00/... ?

Applescript to read a text file and move files to new location

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple ID.