Multiple file importing

Hello folks,

I realise this general issue may have been covered in the past but I will persist. I am using Igor 7.08. I don't usually write Igor code so I used ChatGPT to help me write a script to import 100-odd files with identical formats and headers in one go, including to append the filename to the start of the header, and to skip 8 of the 17 columns. AI removed the skip column part, telling me it was not supported by my version (is that right?), so I ended up with the code below. It compiles ok, however when I implement it in the command line an error message appears with 'Invalid folder path. Check for typos or permissions'. The file path seems fine, and I have tried placing some example files in a folder in Documents as well as Desktop, but same result.

If anyone has some ideas, I'd be keen to learn more.

Regards        

 

Function ADMLoad()

 
    // Register the Mac folder path (must end in colon)
    NewPath/O/Q MyDataPath
    PathInfo MyDataPath

 
    if (V_flag != 0)
        Abort "Invalid folder path. Check for typos or permissions."
    endif

 
    Variable fileIndex = 0
    String fileName, fullPath, baseName
    String wavesBefore, wavesAfter, newWaves
    Variable i, j

 
    do
        fileName = IndexedFile(MyDataPath, fileIndex, ".txt")
        if (strlen(fileName) == 0)
            break
        endif

 
        fullPath = S_path + fileName

 
        Variable lastDot = strsearch(fileName, ".", -1)
        if (lastDot > 0)
            baseName = fileName[0, lastDot - 1]
        else
            baseName = fileName
        endif

 
        wavesBefore = WaveList("*", ";", "")

 
        // Load all columns (Igor 7 doesn’t support column filtering here)
        LoadWave/Q/G/H/J fullPath

 

 
        wavesAfter = WaveList("*", ";", "")
        newWaves = ""

 
        for (j = 0; j < ItemsInList(wavesAfter); j += 1)
            String testName = StringFromList(j, wavesAfter)
            if (WhichListItem(testName, wavesBefore) < 0)
                newWaves += testName + ";"
            endif
        endfor

 
        for (i = 0; i < ItemsInList(newWaves); i += 1)
            String oldName = StringFromList(i, newWaves)
            String newName = baseName + "_" + oldName
            Rename oldName, newName
        endfor

 
        fileIndex += 1
    while (1)

 
End

 

 

 

Function ADMLoad()
 
    // Register the Mac folder path (must end in colon)
    NewPath/O/Q MyDataPath
    PathInfo MyDataPath
 
    if (V_flag != 0)
        Abort "Invalid folder path. Check for typos or permissions."
    endif
 
    Variable fileIndex = 0
    String fileName, fullPath, baseName
    String wavesBefore, wavesAfter, newWaves
    Variable i, j
 
    do
        fileName = IndexedFile(MyDataPath, fileIndex, ".txt")
        if (strlen(fileName) == 0)
            break
        endif
 
        fullPath = S_path + fileName
 
        Variable lastDot = strsearch(fileName, ".", -1)
        if (lastDot > 0)
            baseName = fileName[0, lastDot - 1]
        else
            baseName = fileName
        endif
 
        wavesBefore = WaveList("*", ";", "")
 
        // Load all columns (Igor 7 doesn’t support column filtering here)
        LoadWave/Q/G/H/J fullPath
 
 
        wavesAfter = WaveList("*", ";", "")
        newWaves = ""
 
        for (j = 0; j < ItemsInList(wavesAfter); j += 1)
            String testName = StringFromList(j, wavesAfter)
            if (WhichListItem(testName, wavesBefore) < 0)
                newWaves += testName + ";"
            endif
        endfor
 
        for (i = 0; i < ItemsInList(newWaves); i += 1)
            String oldName = StringFromList(i, newWaves)
            String newName = baseName + "_" + oldName
            Rename oldName, newName
        endfor
 
        fileIndex += 1
    while (1)
 
End

 

The test of V_Flag is backwards. The documentation for PathInfo says:

The PathInfo operation stores information about the named symbolic path in the following variables:
   V_flag    0 if the symbolic path does not exist, 1 if it does exist.
   S_path    Full path using Macintosh path conventions (e.g., "hd:This:That:").

So it should say "if (V_Flag) == 0)".

Regarding the comment "(Igor 7 doesn’t support column filtering here)", the LoadWave operation in Igor Pro 7 does support the /B flag which allows you to skip columns so the comment seems to be wrong.

If you post a couple of files I may be able to write a procedure for you. In that case, please explain further how you want to name the waves. A simple way it could be done is to use a name of the form <filename><columnname> where a given column has a given columnname and <filename> is used to distinguish the waves from one file from the waves from another. If you want to use this name format, let me know what name to use for each column.

Yeah, as Howard said, it would be best if you could post a few demo files together with a short description of what you want to get done exactly and we can help you to set up a loading routine. While it is impressive that ChatGPT was able to come up with Igor code at all, it is clear that this isn't any good. Most of the script could be removed by using a few specialized functions instead. Examples:

- IndexedFile() could be run with index = -1 to get a file list right away, avoiding this implicit while loop

- using ParseFilePath() to get the clean file name instead of cutting strings into parts via lastDot (also the code for getting lastDot is wrong)

- using S_waveNames from LoadWave, which avoids 'finding out' which waves (newWaves) were loaded

... etc.

Thanks for the quick reply and for correcting that line of code.

Of the 17 columns of data in each file, I would only like columns 1,2,4,6,7,10,13,14 and 17 imported. The columns already have a header, which can be incorporated into the new wavename thus:  <filename>_<columnname>. Later, I will simplify the original columnname part of the new name once the data are loaded. I presume I can use:

Rename oldName, newName

with a wildcard? e.g. Rename *_depth_for_growth, *_depth 

3 example files attached.

Regards

 

HD_023_CGR_GRF_100.txt (110.22 KB) HD_023_CGR_GR0_025.txt (110.3 KB) HD_023_CGR_GR0_000.txt (110.22 KB)

Here is a procedure that should work for you. I tested it in Igor Pro 7 and Igor Pro 9.

I started two write this to load waves with names like HD_023_CGR_GR0_000_depth_for_growth but that created wave names that are too long for Igor Pro 7 in which wave names are limited to 31 characters. (In Igor Pro 8 or later wave names can be up to 255 characters.) To work around this issue, I rewrote the code to create waves with names like depth_for_growth in data folders with names like HD_023_CGR_GR0_000. That is what this code does.

#pragma rtGlobals=3     // Use modern global access method and strict wave access.
 
Menu "Load Waves"
    "Load One RND File...", LoadOneRNDFile("", "")
    "Load All RND Files...", LoadAllRNDFilesDF("")
End
 
static StrConstant kFileNameExtension = ".txt"
 
static Function/S GetColumnInfoStr()
    String columnInfoStr = " "
    columnInfoStr += "N='depth_for_growth';"        // 1
    columnInfoStr += "N='growthp_3';"               // 2
    columnInfoStr += "N='_skip_';"                  // 3 growthp_17
    columnInfoStr += "N='growthp_50';"              // 4
    columnInfoStr += "N='_skip_';"                  // 5 growthp_83
    columnInfoStr += "N='growthp_97';"              // 6
    columnInfoStr += "N='age_for_rate';"            // 7
    columnInfoStr += "N='_skip_';"                  // 8 ratep_3
    columnInfoStr += "N='_skip_';"                  // 9 ratep_17
    columnInfoStr += "N='ratep_50';"                // 10
    columnInfoStr += "N='_skip_';"                  // 11 ratep_83
    columnInfoStr += "N='_skip_';"                  // 12 ratep_97
    columnInfoStr += "N='age_for_age_err';"     // 13
    columnInfoStr += "N='AgeMinusErr';"         // 14
    columnInfoStr += "N='_skip_';"                  // 15 AgeMinusErr1SE
    columnInfoStr += "N='_skip_';"                  // 16 AgePlusErr1SE
    columnInfoStr += "N='AgePlusErr';"              // 17
 
    return columnInfoStr
End
 
// LoadOneRNDFile(pathName, fileName)
Function LoadOneRNDFile(pathName, fileName)
    String pathName         // Name of an Igor symbolic path or "" for dialog
    String fileName         // Name of file or full path to file or "" for dialog
 
    // First get a valid reference to a file.
    if ((strlen(pathName)==0) || (strlen(fileName)==0))
        // Display dialog looking for file.
        Variable refNum
        Open/D/R/F=kFileNameExtension/P=$pathName refNum as fileName
        fileName = S_fileName               // S_fileName is set by Open/D
        if (strlen(fileName) == 0)      // User cancelled?
            return -1
        endif
    endif
    
    String columnInfoStr = GetColumnInfoStr()
    
    LoadWave /G /O /D /K=0 /A /B=columnInfoStr /Q /P=$pathName fileName
    Variable numWavesLoaded = V_flag            // V_flag is set by LoadWave
    Variable numWavesToBeLoaded = 9
    if (numWavesLoaded != numWavesToBeLoaded)
        Printf "Error loading file: Expected %d waves, found %d waves\r"
        return -1
    endif
 
    return 0                            // Success
End
 
// LoadAllRNDFilesDF(pathName)
// Loads all files in specified folder with extension specified by kFileNameExtension.
Function LoadAllRNDFilesDF(pathName)
    String pathName                     // Name of symbolic path or "" to get dialog
 
    String fileName
    Variable index=0
 
    if (strlen(pathName)==0)            // If no path specified, create one
        NewPath/O TemporaryPath     // This will put up a dialog
        if (V_flag != 0)
            return -1                       // User cancelled
        endif
        pathName = "TemporaryPath"
    endif
 
    Variable result
    do          // Loop through each file in folder
        fileName = IndexedFile($pathName, index, kFileNameExtension)
        if (strlen(fileName) == 0)          // No more files?
            break                                   // Break out of loop
        endif
        
        // Data folder name is file name with extension removed
        String dfName = ParseFilePath(3, fileName, ":", 0, 0)
        NewDataFolder/O/S $dfName
        result = LoadOneRNDFile(pathName, fileName)
        SetDataFolder ::
        
        if (result != 0)
            String message
            sprintf message, "An error occurred while loading the file \"%s\". Aborting the load.\r", fileName
            Print message
            DoAlert 0, message
            break       
        endif
        
        Printf "Loaded file %d: \"%s\"\r", index, fileName
 
        index += 1
    while (1)
 
    if (Exists("TemporaryPath"))        // Kill temp path if it exists
        KillPath TemporaryPath
    endif
 
    return 0                                // Signifies success
End

 

Hi Howard, A quick update: everything is humming along nicely thanks to your help. There is one tedious task that I don't seem to be able to simplify by copying and pasting from/into the command line: Saving a stack of waves to a delimited .txt file. I have done it the slow way via the menu, but when I copy the code and paste it into the command line and edit it (to update the target columns for exporting), I get a file save error. Below is an example of a manual export, but if I copy and paste that into the command line and change VGR to CGR and alter the filename to HD_CGR_GR.txt, there's an error message. Any help would be greatly appreciated.

Regards, rnd

String/G gWMSaveWaveListStr0 = "HD_70_VGR_GR4_100_GR;HD_70_VGR_GR2_025_GR;HD_47_VGR_GR2_200_GR;HD_23_VGR_GR0_300_GR;HD_100_VGR_GR4_300_GR;HD_23_VGR_GR0_100_GR;HD_100_VGR_GR4_100_GR;HD_100_VGR_GR2_025_GR;HD_47_VGR_GR2_000_GR;HD_23_VGR_GRF_025_GR;HD_47_VGR_GR4_050_GR;HD_70_VGR_GR4_300_GR;HD_23_VGR_GR2_000_GR;HD_70_VGR_GRF_200_GR;HD_47_VGR_GR0_100_GR;"
•gWMSaveWaveListStr0 += "HD_23_VGR_GR4_050_GR;HD_47_VGR_GRF_025_GR;HD_100_VGR_GRF_000_GR;HD_100_VGR_GR0_050_GR;HD_100_VGR_GRF_200_GR;HD_47_VGR_GR0_300_GR;HD_70_VGR_GRF_000_GR;HD_70_VGR_GR0_050_GR;HD_23_VGR_GR2_200_GR;HD_47_VGR_GR2_100_GR;HD_100_VGR_GR4_000_GR;HD_23_VGR_GR0_000_GR;HD_47_VGR_GR4_025_GR;HD_23_VGR_GRF_050_GR;HD_70_VGR_GR4_200_GR;"
•gWMSaveWaveListStr0 += "HD_100_VGR_GR2_050_GR;HD_70_VGR_GR4_000_GR;HD_100_VGR_GR4_200_GR;HD_23_VGR_GR0_200_GR;HD_70_VGR_GR2_050_GR;HD_47_VGR_GR2_300_GR;HD_70_VGR_GR0_025_GR;HD_100_VGR_GRF_300_GR;HD_70_VGR_GRF_100_GR;HD_23_VGR_GR2_300_GR;HD_47_VGR_GR0_200_GR;HD_100_VGR_GR0_025_GR;HD_47_VGR_GRF_050_GR;HD_23_VGR_GR4_025_GR;HD_47_VGR_GR0_000_GR;"
•gWMSaveWaveListStr0 += "HD_23_VGR_GR2_100_GR;HD_70_VGR_GRF_300_GR;HD_100_VGR_GRF_100_GR;HD_70_VGR_GR0_200_GR;HD_23_VGR_GR2_050_GR;HD_47_VGR_GRF_100_GR;HD_47_VGR_GR0_025_GR;HD_23_VGR_GR4_000_GR;HD_100_VGR_GRF_050_GR;HD_100_VGR_GR0_000_GR;HD_23_VGR_GR4_200_GR;HD_100_VGR_GR0_200_GR;HD_47_VGR_GRF_300_GR;HD_70_VGR_GRF_050_GR;HD_70_VGR_GR0_000_GR;"
•gWMSaveWaveListStr0 += "HD_100_VGR_GR2_300_GR;HD_47_VGR_GR4_200_GR;HD_70_VGR_GR4_025_GR;HD_70_VGR_GR2_100_GR;HD_23_VGR_GRF_300_GR;HD_23_VGR_GRF_100_GR;HD_70_VGR_GR2_300_GR;HD_47_VGR_GR2_050_GR;HD_47_VGR_GR4_000_GR;HD_23_VGR_GR0_025_GR;HD_100_VGR_GR4_025_GR;HD_100_VGR_GR2_100_GR;HD_70_VGR_GRF_025_GR;HD_100_VGR_GR0_300_GR;HD_23_VGR_GR4_300_GR;"
•gWMSaveWaveListStr0 += "HD_70_VGR_GR0_100_GR;HD_47_VGR_GRF_200_GR;HD_100_VGR_GRF_025_GR;HD_47_VGR_GRF_000_GR;HD_47_VGR_GR0_050_GR;HD_70_VGR_GR0_300_GR;HD_100_VGR_GR0_100_GR;HD_23_VGR_GR4_100_GR;HD_23_VGR_GR2_025_GR;HD_100_VGR_GR4_050_GR;HD_23_VGR_GR0_050_GR;HD_23_VGR_GRF_000_GR;HD_70_VGR_GR2_200_GR;HD_47_VGR_GR2_025_GR;HD_100_VGR_GR2_000_GR;"
•gWMSaveWaveListStr0 += "HD_47_VGR_GR4_100_GR;HD_47_VGR_GR4_300_GR;HD_70_VGR_GR4_050_GR;HD_100_VGR_GR2_200_GR;HD_70_VGR_GR2_000_GR;HD_23_VGR_GRF_200_GR;"Save/J/M="\n"/W/B gWMSaveWaveListStr0 as "HD_VGR_GR.txt"; KillStrings gWMSaveWaveListStr0

 

but if I copy and paste that into the command line and change VGR to CGR and alter the filename to HD_CGR_GR.txt, there's an error message

What does the error message say?

 

This error means that at least one of the waves you are trying to save is nonexistent in the current folder, so you need to check whether you have made a mistake there. I would recommend to write a small script which accumulates specific waves automatically for saving (i.e., constructs gWMSaveWaveListStr0). This should be not so difficult.

OK, thanks for this advice. I will check the blog to see if there's already something out there that I can edit.

Regards

Try it in small sections to narrow down which wave name is incorrect:

Function Test()
    String/G list = ""
    list += "HD_70_VGR_GR4_100_GR;HD_70_VGR_GR2_025_GR;HD_47_VGR_GR2_200_GR;HD_23_VGR_GR0_300_GR;HD_100_VGR_GR4_300_GR;HD_23_VGR_GR0_100_GR;HD_100_VGR_GR4_100_GR;HD_100_VGR_GR2_025_GR;HD_47_VGR_GR2_000_GR;HD_23_VGR_GRF_025_GR;HD_47_VGR_GR4_050_GR;HD_70_VGR_GR4_300_GR;HD_23_VGR_GR2_000_GR;HD_70_VGR_GRF_200_GR;HD_47_VGR_GR0_100_GR;"
//  list += "HD_23_VGR_GR4_050_GR;HD_47_VGR_GRF_025_GR;HD_100_VGR_GRF_000_GR;HD_100_VGR_GR0_050_GR;HD_100_VGR_GRF_200_GR;HD_47_VGR_GR0_300_GR;HD_70_VGR_GRF_000_GR;HD_70_VGR_GR0_050_GR;HD_23_VGR_GR2_200_GR;HD_47_VGR_GR2_100_GR;HD_100_VGR_GR4_000_GR;HD_23_VGR_GR0_000_GR;HD_47_VGR_GR4_025_GR;HD_23_VGR_GRF_050_GR;HD_70_VGR_GR4_200_GR;"
//  list += "HD_100_VGR_GR2_050_GR;HD_70_VGR_GR4_000_GR;HD_100_VGR_GR4_200_GR;HD_23_VGR_GR0_200_GR;HD_70_VGR_GR2_050_GR;HD_47_VGR_GR2_300_GR;HD_70_VGR_GR0_025_GR;HD_100_VGR_GRF_300_GR;HD_70_VGR_GRF_100_GR;HD_23_VGR_GR2_300_GR;HD_47_VGR_GR0_200_GR;HD_100_VGR_GR0_025_GR;HD_47_VGR_GRF_050_GR;HD_23_VGR_GR4_025_GR;HD_47_VGR_GR0_000_GR;"
//  list += "HD_23_VGR_GR2_100_GR;HD_70_VGR_GRF_300_GR;HD_100_VGR_GRF_100_GR;HD_70_VGR_GR0_200_GR;HD_23_VGR_GR2_050_GR;HD_47_VGR_GRF_100_GR;HD_47_VGR_GR0_025_GR;HD_23_VGR_GR4_000_GR;HD_100_VGR_GRF_050_GR;HD_100_VGR_GR0_000_GR;HD_23_VGR_GR4_200_GR;HD_100_VGR_GR0_200_GR;HD_47_VGR_GRF_300_GR;HD_70_VGR_GRF_050_GR;HD_70_VGR_GR0_000_GR;"
//  list += "HD_100_VGR_GR2_300_GR;HD_47_VGR_GR4_200_GR;HD_70_VGR_GR4_025_GR;HD_70_VGR_GR2_100_GR;HD_23_VGR_GRF_300_GR;HD_23_VGR_GRF_100_GR;HD_70_VGR_GR2_300_GR;HD_47_VGR_GR2_050_GR;HD_47_VGR_GR4_000_GR;HD_23_VGR_GR0_025_GR;HD_100_VGR_GR4_025_GR;HD_100_VGR_GR2_100_GR;HD_70_VGR_GRF_025_GR;HD_100_VGR_GR0_300_GR;HD_23_VGR_GR4_300_GR;"
//  list += "HD_70_VGR_GR0_100_GR;HD_47_VGR_GRF_200_GR;HD_100_VGR_GRF_025_GR;HD_47_VGR_GRF_000_GR;HD_47_VGR_GR0_050_GR;HD_70_VGR_GR0_300_GR;HD_100_VGR_GR0_100_GR;HD_23_VGR_GR4_100_GR;HD_23_VGR_GR2_025_GR;HD_100_VGR_GR4_050_GR;HD_23_VGR_GR0_050_GR;HD_23_VGR_GRF_000_GR;HD_70_VGR_GR2_200_GR;HD_47_VGR_GR2_025_GR;HD_100_VGR_GR2_000_GR;"
//  list += "HD_47_VGR_GR4_100_GR;HD_47_VGR_GR4_300_GR;HD_70_VGR_GR4_050_GR;HD_100_VGR_GR2_200_GR;HD_70_VGR_GR2_000_GR;HD_23_VGR_GRF_200_GR;"
    Save/J/M="\n"/W/B list as "HD_VGR_GR.txt"
End

If that generates an error, break it down further.

Or use this function to test if the waves exist:

Function Test2()
    String/G list = ""
    list += "HD_70_VGR_GR4_100_GR;HD_70_VGR_GR2_025_GR;HD_47_VGR_GR2_200_GR;HD_23_VGR_GR0_300_GR;HD_100_VGR_GR4_300_GR;HD_23_VGR_GR0_100_GR;HD_100_VGR_GR4_100_GR;HD_100_VGR_GR2_025_GR;HD_47_VGR_GR2_000_GR;HD_23_VGR_GRF_025_GR;HD_47_VGR_GR4_050_GR;HD_70_VGR_GR4_300_GR;HD_23_VGR_GR2_000_GR;HD_70_VGR_GRF_200_GR;HD_47_VGR_GR0_100_GR;"
    list += "HD_23_VGR_GR4_050_GR;HD_47_VGR_GRF_025_GR;HD_100_VGR_GRF_000_GR;HD_100_VGR_GR0_050_GR;HD_100_VGR_GRF_200_GR;HD_47_VGR_GR0_300_GR;HD_70_VGR_GRF_000_GR;HD_70_VGR_GR0_050_GR;HD_23_VGR_GR2_200_GR;HD_47_VGR_GR2_100_GR;HD_100_VGR_GR4_000_GR;HD_23_VGR_GR0_000_GR;HD_47_VGR_GR4_025_GR;HD_23_VGR_GRF_050_GR;HD_70_VGR_GR4_200_GR;"
    list += "HD_100_VGR_GR2_050_GR;HD_70_VGR_GR4_000_GR;HD_100_VGR_GR4_200_GR;HD_23_VGR_GR0_200_GR;HD_70_VGR_GR2_050_GR;HD_47_VGR_GR2_300_GR;HD_70_VGR_GR0_025_GR;HD_100_VGR_GRF_300_GR;HD_70_VGR_GRF_100_GR;HD_23_VGR_GR2_300_GR;HD_47_VGR_GR0_200_GR;HD_100_VGR_GR0_025_GR;HD_47_VGR_GRF_050_GR;HD_23_VGR_GR4_025_GR;HD_47_VGR_GR0_000_GR;"
    list += "HD_23_VGR_GR2_100_GR;HD_70_VGR_GRF_300_GR;HD_100_VGR_GRF_100_GR;HD_70_VGR_GR0_200_GR;HD_23_VGR_GR2_050_GR;HD_47_VGR_GRF_100_GR;HD_47_VGR_GR0_025_GR;HD_23_VGR_GR4_000_GR;HD_100_VGR_GRF_050_GR;HD_100_VGR_GR0_000_GR;HD_23_VGR_GR4_200_GR;HD_100_VGR_GR0_200_GR;HD_47_VGR_GRF_300_GR;HD_70_VGR_GRF_050_GR;HD_70_VGR_GR0_000_GR;"
    list += "HD_100_VGR_GR2_300_GR;HD_47_VGR_GR4_200_GR;HD_70_VGR_GR4_025_GR;HD_70_VGR_GR2_100_GR;HD_23_VGR_GRF_300_GR;HD_23_VGR_GRF_100_GR;HD_70_VGR_GR2_300_GR;HD_47_VGR_GR2_050_GR;HD_47_VGR_GR4_000_GR;HD_23_VGR_GR0_025_GR;HD_100_VGR_GR4_025_GR;HD_100_VGR_GR2_100_GR;HD_70_VGR_GRF_025_GR;HD_100_VGR_GR0_300_GR;HD_23_VGR_GR4_300_GR;"
    list += "HD_70_VGR_GR0_100_GR;HD_47_VGR_GRF_200_GR;HD_100_VGR_GRF_025_GR;HD_47_VGR_GRF_000_GR;HD_47_VGR_GR0_050_GR;HD_70_VGR_GR0_300_GR;HD_100_VGR_GR0_100_GR;HD_23_VGR_GR4_100_GR;HD_23_VGR_GR2_025_GR;HD_100_VGR_GR4_050_GR;HD_23_VGR_GR0_050_GR;HD_23_VGR_GRF_000_GR;HD_70_VGR_GR2_200_GR;HD_47_VGR_GR2_025_GR;HD_100_VGR_GR2_000_GR;"
    list += "HD_47_VGR_GR4_100_GR;HD_47_VGR_GR4_300_GR;HD_70_VGR_GR4_050_GR;HD_100_VGR_GR2_200_GR;HD_70_VGR_GR2_000_GR;HD_23_VGR_GRF_200_GR;"
    
    Variable numItems = ItemsInList(list)
    Variable i
    for (i=0; i<numItems; i+=1)
        String name = StringFromList(i, list)
        WAVE/Z w = $name
        if (!WaveExists(w))
            Printf "Wave does not exist: %s\r", name
        endif
    endfor
End