Issue
I have the following script:
#!/bin/zsh
old_IFS="$IFS"
IFS='|'
files_to_exclude="$*"
IFS="$old_IFS"
set -- -f --
set -- "$@" ./^("${files_to_exclude}")
rm "$@"
and I expect the following command to be executed (if the script was invoked with arguments test.txt
, cover.jpg
and 01.\ Filename.flac
):
rm -f -- ./^(test.txt|cover.jpg|01.\ Filename.flac)
Instead, when executing the script I get the following error on line 11:
number expected
.
I presume that the reason for it is the glob character ^
which refuses to be parsed somehow. I have used this resource to write the script.
I have also tried eval
but to no avail either.
Is there a way to get this working?
P.S. I have just tried doing this using zsh
's function alias and it is not working either:
rm-excluding() {
rm -f -- ./^($*)
}
Invoking the above with rm-excluding a b
results in:
rm-excluding:1: bad pattern: ./^(a
Solution
I think there's a bit of an XY problem going on here; you're not explaining the what, you're focusing on a rather convoluted how instead. It looks like you're trying to build up a glob pattern that's supposed to expand to all but a list of files known at runtime.
One way, using zsh
's more advanced parameter expansion features to first join the positional parameters together with |
characters while building the pattern, and then to force filename expansion on it (Which can also be enabled globally with the GLOB_SUBST
option I prefer to do it case-by-case):
#!/usr/bin/env zsh
# Just in case it's turned off somehow by your setup
setopt EXTENDED_GLOB
# Build the pattern by joining position parameters with pipes
excluded="^(${(j:|:)argv})"
# And expand with zsh's ${~spec} form of parameter expansion
# to force the expanded value to undergo filename expansion
print -l -- ${~excluded} # Replace with rm when you're sure it's working right
Note the use of a variable named argv
; it's an array version of the positional parameters that can be used instead of $*
or $@
in zsh
that often ends up being simpler to work with.
You could also avoid a complicated glob completely by using array difference expansion (:|
):
# Make an array with all matching files and remove the ones in $argv
typeset -a allfiles=(*)
print -l -- ${allfiles:|argv}
which is the option I'd prefer; it's simpler with fewer moving parts for unexpected behavior.
Answered By - Shawn Answer Checked By - Katrina (WPSolving Volunteer)