why doesn't *.abc match a file named .abc? - macos

I thought I understood wildcards, till this happened to me. Essentially, I'm looking for a wild card pattern that would return all files that are not named .gitignore. I came up with this, which seems to work for all cases I could conjure:
ls *[!{gitignore}]
To really validate if this works, I thought I'd negate the expression and see if it returns the file named .gitignore (actually any file that ended with gitignore; so 1.gitignore should also be returned). To that effect, I thought the negated expression would be:
ls *[{gitignore}]
However, this expression doesn't return a files named .gitignore (although it returns a file named 1.gitignore).
Essentially, my question, after simplification, boils down to:
Why doesn't *.abc match a file that is named .abc
I think I can take it from there.
PS:
I am working on Mac OSX Lion (10.7.4)
I wanted to add a clause to .gitignore such that I would ignore every file, except .gitignore in a given folder. So I ended up adding * in the .gitignore file. Result was, git ended up ignoring .gitignore :)
From the numerous searches I've made on google - Use the asterisk character (*) to represent zero or more characters.

I assume you're using Bash. From the Bash manual:
When a pattern is used for filename expansion, the character ‘.’ at the start of a filename or immediately following a slash must be matched explicitly, unless the shell option dotglob is set.
.gitignore patterns, however, are treated differently:
Otherwise, git treats the pattern as a shell glob suitable for consumption by fnmatch(3) with the FNM_PATHNAME flag: wildcards in the pattern will not match a / in the pathname.
According to the fnmatch(3) docs, a leading dot has to be explicitly matched only if the FNM_PERIOD flag is set, so *gitignore as a gitignore pattern would match .gitignore.
There is an easier way to accomplish this, though. To have .gitignore ignore everything except .gitignore:
*
!.gitignore

If you want to ignore everything except the gitignore file, use this as the file:
*
!.gitignore
Lines starting with an exclamation point are interpreted as exceptions.

Related

Bash glob, how to OR over strings of non unit length?

I have in a directory a bunch of files. Each file's basename ends with a two digit number and a letter, such as file_01A.txt, file_03B.txt, file_13A.txt.
In a terminal using bash (I assume, working on a mac osx) I use
ls *01*[AB]*.txt
returns all files such as 01A and 01B. This makes sense to me.
ls *02*[AB]*.txt
returns similarly all files such as 02A and 02B.
Now I want to return all files 01A, 01B, 02A, 02B. Hence I want something like:
ls *(01 or 02)*[AB]*.txt
Attempt 1: I tried with | but that throws an error.
Attempt 2: ls *[01,02]*[AB]*.tex but that gives the 03 files too, since I assume it is interpreting the 01 and 02 as individual matches.
Attempt 3: ls *["01","02"]*[AB]*.tex is the same again.
It's not hard to articulate a single wildcard which matches your requirement.
ls *0[12]*[AB]*.tex
In the general case, use multiple wildcards if you can't articulate a single one. Notice that the shell expands them in the order you write them, and if they both match some files, there will be duplicates in the expansion.
ls *01*[AB]*.tex *02*[AB]*.tex
You seem to be confused about what the metacharaters mean. * matches any string, ? matches any character, and [abc] matches any one character which is listed between the square brackets. [!abc] watches a single character which is not a, b, or c. Bash also supports an extension called brace expansion, where foo{bar,quux} is basically an abbreviation of foobar fooquux. Your attempt could thus be rearticulated as
ls *{01,02}*[AB].tex
though the repeated prefix 0 is obviously redundant, and would better be left outside the braces, and then you might as well switch back to straight square brackets.
There is also a separate extended globbing syntax which allows for more elaborate wildcards. See the reference manual for details.

How can I debug .gitignore file handling?

I’m having lots of trouble convincing git to ignore files in my project.
Basically, sometimes it works, sometimes it just seems to ignore the .gitignore file for no obvious reason. (By “seems” I mean that there are patterns in it that look as if they should exclude something, but that something is not excluded.)
There’s a 'git check-ignore' command, but it only says which pattern matched a file. But I can’t find any option to make it say which patterns it’s found and where, nor why those patterns do not match a file.
Is there a way to do this kind of debugging?
P.S. There is a single issue which I did find, and I’m mentioning it here in case it helps others:
I was adding patterns using “echo pattern >> .gitignore”, which at least on my system results in spaces at the of the line (i.e., everything between “echo” and “>>” is echoed in the file, except for the first space character after “echo”).
Git does not trim those spaces when matching patterns, so for the command above it wouldn’t match a file named “pattern” but it would match “pattern{space}”.
I think most of my issues stem from this. Those extra spaces are hard to notice, so I’d still like a debug command that makes sure I notice them, if there is one.
Edit #1:
Yes, I did try -v. For example:
> mkdir test
> touch test/file.txt
> echo test >> .gitignore
> git check-ignore -v test/file.txt
(nothing is printed)
> echo test>> .gitignore
> git check-ignore -v test/cuc.txt
.gitignore:8:test test/cuc.txt
Note the extra space in the first echo line, which makes it enter “test[space]” as a pattern. As I mentioned, “check-ignore” tells you what matched, but it doesn’t tell you what didn’t nor why.

rsync: --include-from vs. --exclude-from what is the actual difference?

In the documentation, it mentions these as being files containing lists of either patterns to include or patterns to exclude. However, that implies for inclusions, everything is considered an exclusion except where things match patterns. So for example, an include file containing:
/opt/**.cfg
Should only include any file named *.cfg that exists anywhere under a directory named opt any where in the tree. So it would match the following:
/opt/etc/myfile.cfg
/some/dir/opt/myfile.cfg
/notopt/opt/some/other/dir/myfile.cfg
I'd therefore expect it to implicitly exclude anything else. But that doesn't seem to be the case, since I am seeing this in the itemized output:
*deleting etc/rc.d/init.d/somescript
So what is the deal with --include-from and --exclude-from? Are they just aliases for --filter-from?
rsync doesn't work like that. Any file with a filename pattern that does not match any of the include or exclude patterns are considered to be included. In other words, think of the include pattern as a way of overriding exclude pattern.
From the docs (emphasis mine):
Rsync builds an ordered list of include/exclude options as specified on the command line. Rsync checks each file and directory name against each exclude/include pattern in turn. The first matching pattern is acted on. If it is an exclude pattern, then that file is skipped. If it is an include pattern then that filename is not skipped. If no matching include/exclude pattern is found then the filename is not skipped.
So, if you want to include only specific files, you first need to include those specific files, then exclude all other files:
--include="*/" --include="*.cfg" --exclude="*"
Couple of things to note here:
The include patterns have to come before the excludes, because the first pattern that matches is the one that gets considered. If the file name matches the exclude pattern first, it gets excluded.
You need to either include all subdirectories individually, like --include="/opt" --include="/opt/dir1" etc. for all subdirectories, or use --include="*/" to include all directories (not files). I went with the second option for brevity.
It is quirky and not very intuitive. So read the docs carefully (the "EXCLUDE PATTERNS" section in the link) and use the --dry-run or -n option to make sure it is going to do what you think it should do.
If you (like me) have a hard time to wrap your head around the FILTER RULES-section in the man-pages but have a basic understanding of find, you could use that instead.
Say you whant to sync everyting with a specific date (ex 2016-02-01) in either the file-name or in a directory-name from /storage/data to rsync_test. Do something like this:
cd /storage/data
find . -name '*2016-02-01*' \
| rsync --dry-run -arv --files-from=- /storage/data /tmp/rsync_test

Linux shell list file what's the difference bewteen tmp/**/* and tmp/*

I encounter one problem about the file system in the shell.
what's difference between tmp/**/* and tmp/*?
I make the experiment in my system,
have this directory dir2
dir2
-->dir1
-->xx2
-->ff.txt
and I run ls dir2/*:
dir2/ff.txt
dir2/dir1:
xx2
then I run ls dir2/**/*:
dir2/dir1/xx2
So it means the ** is to ignore this directory(like ignore the dir1),
Can some one help me ?
I think there's a formatting issue in the question test, but I'll answer based on the question title and examples.
There shouldn't be any difference between a single and double asterisk at any single level of the path. Either expression matches any name, except for hidden ones which start with a dot (this can be changed by shell options). So:
tmp/**/* (equivalent to tmp/*/*) is expanded to all names which are nested two levels deep in tmp. The first asterisk expands only to directories and not files at the first level because it's followed by a slash.
tmp/* expands to anything nested one level deep inside tmp.
To this comes the fact that ls will list contents of directory if a directory is given on its command line. This can be overridden by adding -d option to ls.

Makefile problem with files beginning with "#"

I have a directory "FS2" that contains the following files:
ARGH
this
that
I have a makefile with the following contents.
Template:sh= ls ./FS2/*
#all: $(Template)
echo "Template is: $(Template)"
touch all
When I run "clearmake -C sun" and the file "all" does not exist, I get the following output:
"Template is: ./FS2/#ARGH# ./FS2/that ./FS2/this"
Modifying either "this" or "that" does not cause "all" to be regenerated. When run with "-d" for debug, the "all" target is only dependent on the directory "./FS2", not the three files in the directory. I determined that when it expands "Template", the "#" gets treated as the beginning of a comment and the rest of the line is ignored!
The problem is caused by an editor that when killed leaves around files that begin with "#". If one of those files exists, then no modifications to files in the directory causes "all" to be regenerated.
Although, I do not want to make compilation dependent on whether a temporary file has been modified or not and will remove the file from the "Template" variable, I am still curious as to how to get this to work if I did want to treat the "#ARGH#" as a filename that the rule "all" is dependent on. Is this even possible?
I have a directory "FS2" that contains the following files: #ARGH# ...
Therein lies your problem. In my opinion, it is unwise using "funny" characters in filenames. Now I know that those characters are allowed but that doesn't make them a good idea (ASCII control characters like backspace are also allowed with similar annoying results).
I don't even like spaces in filenames, preferring instead SomethingLikeThis to show independent words in a file name, but at least the tools for handling spaces in many UNIX tools is known reasonably well.
My advice would be to rename the file if it was one of yours and save yourself some angst. But, since they're temporary files left around by an editor crash, delete them before your rules start running in the makefile. You probably shouldn't be rebuilding based on an editor temporary file anyway.
Or use a more targeted template like: Template:sh= ls ./FS2/[A-Za-z0-9]* to bypass those files altogether (that's an example only, you should ensure it doesn't faslely exclude files that should be included).
'#' is a valid Makefile comment char, so the second line is ignored by the make program.
Can you filter out (with grep) the files that start with # and process them separately?
I'm not familiar with clearmake, but try replacing your template definition with
Template:sh= ls ./FS2/* | grep -v '#'
so that filenames containing # are not included in $(Template).
If clearmake follows the same rules as GNU make, then you can also re-write your target using something like Template := $(wildcard *.c) which will be a little more intelligent about files with oddball names.
If I really want the file #ARGH# to contribute to whether the target all should be rebuilt as well as be included in the artifacts produced by the rule, the Makefile should be modified so that the line
Template:sh= ls ./FS2/*
is changed to
Template=./FS2/*
Template_files:sh= ls $(Template)
This works because $(Template) will be replaced by the literal string ./FS2/* after all and in the expansion of $(Template_files).
Clearmake (and GNU make) then use ./FS2/* as a pathname containing a wildcard when evaluating the dependencies, which expands in to the filenames ./FS2/#ARGH# ./FS2/that ./FS2/this and $(Template_files) can be used in the rules where a list of filenames is needed.

Resources