FilterCmd - Run another command on files matching a wildcard

Overview:

This script adds a FilterCmd command, which allows you to run another command on only a subset of the selected files, using a wildcard pattern. It will also leave all files selected which started off selected.

The purpose is to help in situations where you want to select a bunch of different files, then run various actions on those files, with some only affecting files of a certain type, while leaving everything selected for the next action(s).

Notes:

  • If you just want to do a filtered copy, move or delete, you don't need this script. Those commands have filtering built-in.

  • Many commands also accept wildcards, but if you specify them they tend to ignore the selection and work on all files that match the wildcards. (Except where they have separate FILE and PATTERN arguments, or similar, like the Rename command.) But if your aim is to be able to Select-All and then click a button to only affect certain files, then you probably don't need this script.

  • If you don't care about leaving things selected afterwards, ready for subsequent commands, and you just want to exclude certain files from a single command, then you don't need this script. You can use the Select command to deselect things, and then run whatever you wanted afterwards, all as part of a single button.

Installation:

  • Download FilterCmd.js.txt (2.0 KB)
  • Drag it to Preferences / Toolbars / Scripts.
  • With the script installed, you can create toolbar buttons or hotkeys which use the FilterCmd command, as described below.

Arguments:

  • FILE (multiple)

    Normally, the command acts on the selected files. You can use this to specify the full path to one or more files to act on instead, in which case the selection is ignored. This can be useful if you want to run commands from outside of Opus while passing them multiple files at once, with optional filtering.

    Files which do not exist will be ignored entirely. Folders will also be ignored, unless you change the filesOnly variable within the script code.

    You must give the full path to all files; filenames on their own or other types of relative paths will not work.

    As usual, if a path contains a space then it must have "quotes" around it.

    You can combine this with the PATTERN argument or use it on its own.

  • PATTERN (keyword)

    Specify the wildcard pattern which files must match.

    Note that only files are matched. Folders are ignored. You can change the filesOnly variable in the code if you want this to work on folders, but it seems unlikely.

  • CMD (raw)

    The command to run. This is a "raw" argument, so literally everything after it is considered part of the command you want to run, and you don't need extra quotes, except where they would be needed for the command itself.

Examples:

For all selected JPG, GIF and PNG files, set their comment fields to `Hello World":

FilterCmd PATTERN *.(JPG|JPEG|GIF|PNG) CMD SetAttr META "comment:Hello World"

Open the Properties dialog for all selected TXT files only:

FilterCmd PATTERN *.TXT CMD Properties

Open the Properties dialog for C:\Windows\notepad.exe and C:\Windows\explorer.exe:

FilterCmd FILE "C:\Windows\notepad.exe" "C:\Windows\explorer.exe" CMD Properties

History:

  • 1.1 (14/Jul/2020): Added FILE argument which lets you specify a list of files on the command line instead of using the selected files.
  • 1.0 (08/Jul/2020): Initial version.

Script code:

The script code from the download above is reproduced below. This is for people browsing the forum for scripting techniques. You do not need to care about this code if you just want to use the script.

function OnInit(initData)
{
	initData.name = "FilterCmd";
	initData.version = "1.1";
	initData.copyright = "(c) 2020 Leo Davidson";
	initData.url = "https://resource.dopus.com/t/filtercmd-run-another-command-on-files-matching-a-wildcard/36059";
	initData.desc = "Run a command on a subset of the selected files";
	initData.default_enable = true;
	initData.min_version = "12.0";

	var cmd = initData.AddCommand();
	cmd.name = "FilterCmd";
	cmd.method = "OnFilterCmd";
	cmd.desc = "Run a command on a subset of the selected files.";
	cmd.label = "FilterCmd";
	cmd.template = "PATTERN/K,FILE/M,CMD/R";
	cmd.hide = false;
	cmd.icon = "recursivefilter";
}

function OnFilterCmd(scriptCmdData)
{
	var args = scriptCmdData.func.args;

	if ((!args.got_arg.pattern && !args.got_arg.file) || !args.got_arg.cmd)
		return;

	var filesOnly = true;

	var tab = scriptCmdData.func.sourcetab;

	var cmdButton = scriptCmdData.func.command;
	cmdButton.deselect = false; // Leave everything selected

	// Make a new command object, independent of the original one
	var cmd = DOpus.Create.Command();
	cmd.SetSourceTab(tab);

	var wild = null;
	
	if (args.got_arg.pattern)
	{
		wild = DOpus.FSUtil.NewWild(args.pattern, "f");
	}

	var anyFiles = false;

	if (args.got_arg.file)
	{
		var vecFiles = args.file;
		var fsu = DOpus.FSUtil;

		for (var eSel = new Enumerator(args.file); !eSel.atEnd(); eSel.moveNext())
		{
			var item = fsu.GetItem(eSel.item());
			
			if (item.attr !== undefined)
			{
				if ((!filesOnly || !item.is_dir) && (!wild || wild.Match(item.name)))
				{
					cmd.AddFile(item);
					anyFiles = true;
				}
			}
		}
	}
	else
	{
		for (var eSel = new Enumerator(tab.selected); !eSel.atEnd(); eSel.moveNext())
		{
			var item = eSel.item();

			if ((!filesOnly || !item.is_dir) && (!wild || wild.Match(item.name)))
			{
				cmd.AddFile(item);
				anyFiles = true;
			}
		}
	}

	if (anyFiles)
	{
		cmd.RunCommand(args.cmd);
	}
}
2 Likes

I notice a few minor nit-picking details which should have nothing to do with its functionality (and I could be wrong, of course):

  • Under Notes, you wrote

Supposed to be “you probably DO need this script”, right?

  • Under History, you give the date of this initial version as 08/Jun/2020, though I imagine you really meant today?

But thanks for contributing this.

No, you really don't need the script if that's all you want to do.

Yep, typo. Fixed now. Thanks!

This works like a charm in a handful of tests. Thanks again, Leo!

I have a quick question, though not directly related to the function of your excellent script but noticed while testing it, so it will be a separate thread. Stay tuned.

1 Like

Root post updated with v1.1: