Zsh glob: Get everything except stuff in a certin folder - zsh

Trying to find all files except those inside vendor/ folders, but why is this failing?
setopt extendedglob
for file in **/*~vendor/; do
done

See if this does what you're looking for:
setopt extendedglob
print -l ^vendor/**/*(.)
The *~ negation syntax usually needs parentheses in order to determine where the expression after the tilde ends. Your pattern is requesting all files and folders except those where the glob result name ends with vendor/. The glob result never includes the trailing slash, so you end up with all of the files and folders.
Adding parens will change the behavior of that pattern, but probably not in a useful way. This will result in a list of all of the directories where the last component is not vendor:
print -l **/(*~vendor)/
so x/y, x/y/vendor/z, and vendor/a will be included, but x/y/vendor will not.
The parentheses limit the 'not' pattern to just one piece of the path. In order to exclude matches at the top-level, the tested component needs to be at the front of the pattern:
print -l (*~vendor)/**/*
The very first pattern above uses the ^ syntax to produce the same results. The (.) glob qualifier in that pattern limits the globbing to plain files, so directories are not included.
Another variation that may be useful - this will exclude directories that have any component named vendor. It is similar to find -prune:
print -l (^vendor/)#*(.)
This will produce a list of all files except those in subdirectories with names like vendor/x, a/vendor and a/vendor/b.

Related

Unix tree ignore by pattern

man tree says
-I pattern
Do not list those files that match the wild-card pattern.
However, when I specify:
$ tree . -I .*~ -I *egg-info
I still see:
tree . -I .*~ -I *egg-info -I *.pyc
.
├── bin
├── LICENSE
├── Makefile
├── Makefile~
etc., it's still showing Makefile~ even though there's a terminal ~
What's the right syntax to get tree to ignore the pattern I have given it?
I see a few possibilities in your command. (Not knowing the 'flavor' of your unix, it's hard to pinpoint exactly).
.* Unix has "hidden" files. These are files whose name starts with a DOT. In Reg Ex, DOT ASTERISK means 0 or more characters. With file names, DOT ASTERISK means all hidden files and no visible files. Makefile~ is a visible file, not a hidden file, so it will not be excluded. You may need to replace DOT ASTERISK TILDE with ASTERISK TILDE.
-I = Exclude files, not exclude directories. If Makefile~ is a directory name, the -I may not exclude it.
File Globbing can bite you. -I M* will read the current directory and expand M* into every filename in the current directory. So, -I M* couild be "globbed" (or replaced) with -I Milk Money Margaret_is_a_Beauty. Use quotation marks around your wildcards. Try -I ".*~"or -I '.*~'
As per the man page extract you quoted, tree uses "wild-card pattern" which is a common synonym for "glob" or "glob pattern". In this paradigm * is the syntax for "a any number of any character".
(.* is the equivalent form in the regex paradigm.)
Your first ignore pattern -I .*~ is then searching for a . character followed by a * then a ~.
In this you simply mixed up the regex form with the glob form.
And as you can see, your other patterns worked the way you wanted because they don't have a prepended . in them.

rsync only folders and files in special sub directory

I have the following structure
I want to copy only folders, subfolders and files, which are located in "_bearbeitet".
I am trying it with the following options
--archive --hard-links --ignore-errors --force --exclude=* --include=/_bearbeitet
You have your rules in the wrong order, and your glob is too general.
Try this:
--include=/_bearbeitet --exclude='/*'
So altogether:
rsync -aH --ignore-errors --force --include=/_bearbeitet --exclude='/*' $src $dest
The rule is that, for each file, rsync will use the first include/exclude rule that matches, and will include anything that matches no rule.
So, first list what you want to include: /_barbeitet matches the named directory at the top level only.
Then list what you want to exclude after: /* matches all files and directories at the top level only. Note that * on it's own would exclude all files and directories anywhere, including files and directories inside an explicitly included directory.
You should also take care to put quotes around * in patterns or else the shell will expand them before calling rsync, which is not what you want.

Globbing not working as expected

I would like to list all plain files that are not python scripts in zsh.
Why does the following "code" not work and what is the proper solution?
ls -l *(.)~*.py
UPDATE:
I have setopt extended_glob in my .zshrc.
And
ls -ld *~*.py``
works as expected.
(I added the -d in the command to prevent directories from getting expanded).
The problem is that ~ is a glob operator (that also requires EXTENDED_GLOB be set), while (.) is a glob qualifier, which means it must be added to the end of the entire pattern, not used in the middle. Use
ls *~*.py(.)
instead. That is, *~*.py is your pattern (all files not ending in .py), and (.) is applied to the results. (Perhaps yet another way to put it is to say that glob operators can only work on unqualified patterns.)

How to make the glob() function also match hidden dot files in Vim?

In a Linux or Mac environment, Vim’s glob() function doesn’t match dot files such as .vimrc or .hiddenfile. Is there a way to get it to match all files including hidden ones?
The command I’m using:
let s:BackupFiles = glob("~/.vimbackup/*")
I’ve even tried setting the mysterious {flag} parameter to 1, and yet it still doesn’t return the hidden files.
Update: Thanks ib! Here’s the result of what I’ve been working on: delete-old-backups.vim.
That is due to how the glob() function works: A single-star pattern
does not match hidden files by design. In most shells, the default
globbing style can be changed to do so (e.g., via shopt -s dotglob
in Bash), but it is not possible in Vim, unfortunately.
However, one has several possibilities to solve the problem still.
First and most obvious is to glob hidden and not hidden files
separately and then concatenate the results:
:let backupfiles = glob(&backupdir..'/*').."\n"..glob(&backupdir..'/.[^.]*')
(Be careful not to fetch the . and .. entries along with hidden files.)
Another, perhaps more convenient but less portable way is to use
the backtick expansion within the glob() call:
:let backupfiles = glob('`find '..&backupdir..' -maxdepth 1 -type f`')
This forces Vim to execute the command inside backticks to obtain
the list of files. The find shell command lists all files (-type f)
including the hidden ones, in the specified directory (-maxdepth 1
forbids recursion).

Unix wildcard selectors? (Asterisks)

In Ryan Bates' Railscast about git, his .gitignore file contains the following line:
tmp/**/*
What is the purpose of using the double asterisks followed by an asterisk as such: **/*?
Would using simply tmp/* instead of tmp/**/* not achieve the exact same result?
Googling the issue, I found an unclear IBM article about it, and I was wondering if someone could clarify the issue.
It says to go into all the subdirectories below tmp, as well as just the content of tmp.
e.g. I have the following:
$ find tmp
tmp
tmp/a
tmp/a/b
tmp/a/b/file1
tmp/b
tmp/b/c
tmp/b/c/file2
matched output:
$ echo tmp/*
tmp/a tmp/b
matched output:
$ echo tmp/**/*
tmp/a tmp/a/b tmp/a/b/file1 tmp/b tmp/b/c tmp/b/c/file2
It is a default feature of zsh, to get it to work in bash 4, you perform:
shopt -s globstar
From http://blog.privateergroup.com/2010/03/gitignore-file-for-android-development/:
(kwoods)
"The double asterisk (**) is not a git thing per say, it’s really a linux / Mac shell thing.
It would match on everything including any sub folders that had been created.
You can see the effect in the shell like so:
# ls ./tmp/* = should show you the contents of ./tmp (files and folders)
# ls ./tmp/** = same as above, but it would also go into each sub-folder and show the contents there as well."
According to the documentation of gitignore, this syntax is supported since git version 1.8.2.
Here is the relevant section:
Two consecutive asterisks (**) in patterns matched against full pathname may have special meaning:
A leading ** followed by a slash means match in all directories. For example, **/foo matches file or directory foo anywhere, the
same as pattern foo. **/foo/bar matches file or directory bar
anywhere that is directly under directory foo.
A trailing /** matches everything inside. For example, abc/** matches all files inside directory abc, relative to the location of
the .gitignore file, with infinite depth.
A slash followed by two consecutive asterisks then a slash matches zero or more directories. For example, a/**/b matches a/b,
a/x/b, a/x/y/b and so on.
Other consecutive asterisks are considered invalid.

Resources