How does this bash function for removing all but some files work?
I've found the following script on commandlinefu.com (the example is not online anymore):
rmbut() {
local x=("$@")
IFS=, rm -rf *[!"${x[*]}"]
}
It deletes all files and directories but the ones named on the command line.
Could you explain the following:
- What is happening on the first line?
$@means all arguments, but why is it put inside parentheses? - I've read about
IFSbut never actually used it, what is its usage here? - What is 开发者_JAVA百科achieved with
*[!"${x[*]}"]? I can't understand how to split it into something I know.
local x=("$@") creates an array which is a copy of all the arguments ($@ is itself an array).
IFS=, sets the internal field separator to a comma.
IFS=, rm -rf *[!"${x[*]}"] says to remove all files that do not end in any character passed as arguments. Since * is used as the index to the array and the variable is quoted it is expanded to a single string and the spaces that would normally separate the elements of the array are replaced by the contents of IFS (a comma in this case).
rmbut a b c
resolves to rm -rf *[!a,b,c] which would also not remove files that end in a comma.
I think the function could be simplified to:
rmbut() {
IFS= rm -rf *[!"$*"]
}
but its behavior would be subtly different. This version sets IFS to null so the example above would resolve to rm -rf *[!abc] which would remove files that end in a comma (a comma would have to be passed explicitly as an argument to preserve such files). However, that behavior could be returned by setting IFS=, (it's simply not necessary to copy the array).
# create an array x, containing arguments to the function
local x=("$@")
# unset the IFS variable. This make double quoted arrays expand to single words w/o separators
IFS=
# remove files matching a pattern, i.e. not ending with a character from the array x
rm -rf *[!"${x[*]}"]
加载中,请稍侯......
精彩评论