I read Vim's help on file-searching where * and ** file searching operators are explained (both cited below). While I grasp that ** matches only directories (with limitation of 30 directories deep by default) and * matches everything (including /), I don't think I understand why there is a need for both of them and what are the use cases for each.
Also, how to match only the files in the listed directory? directory/* would match files in subdirectories (e.g. directory/subdirectory/) as well, right? Wouldn't they compliment each other better if * would match only files in the listed directory (without subdirectories)?
Vim documentation:
The usage of '*' is quite simple: It matches 0 or more characters. In a
search pattern this would be ".*". Note that the "." is not used for file
searching.
'**' is more sophisticated:
- It ONLY matches directories.
- It matches up to 30 directories deep by default, so you can use it to
search an entire directory tree
- The maximum number of levels matched can be given by appending a number
to '**'.
No, just like in wildcards, * does not match /.
In all of the (quite few) cases where these are used, vim is either only looking for files or only looking for directories, so there is no problem with directories matching where you want files.
Related
I have found a simple solution to my actual requirement, but I would still like to understand how to use the regex equivalent of the single character wildcard ? which we use for filtering ... in say ls
I would like to rename a group of files which differ by one character.
FROM
Impossible-S01E01-x264.mkv
Impossible-S01E02-x264.mkv
Impossible-S01E03-x264.mkv
Impossible-S01E04-x264.mkv
Impossible-S01E05-x264.mkv
TO
Impossible-S01E01.mkv
Impossible-S01E02.mkv
Impossible-S01E03.mkv
Impossible-S01E04.mkv
Impossible-S01E05.mkv
As I said above, my simple solution is:
rename s/-x264// *.mkv
That sorts out my needs - all good and well - but I really want to understand my first approach:
To list the files, I can use:
ls Impossible-S01E0?-x264.mkv
So what I was trying for the rename was:
rename s/Impossible-S01E0?-x264.mkv/Impossible-S01E0?.mkv/ *.mkv
I have read up here:
How do regular expressions differ from wildcards used to filter files
And here:
Why does my regular expression work in X but not in Y?
I see this:
. matches any character (or any character except a newline).
I just can't seem to wrap my head around how to use that - hoping someone will explain for my education.
{ edit: missed a backslash \ }
So, regular expressions aren't globs. If you wanted to keep the middle (e.g. catch the season/ep) and replace everything else, you'd need to use capture groups. e.g. s/^.*(S\d+E\d+).*\.(.*?)$/Foo-$1.$2/
This would extract an SxxExx and the file extension, throw everything else away, and compose a new filename.
In a bit more detail it:
Matches everything from the start until an SxxExx (where xx is actually any number of digits)
Captures the contents of SxxExx
Matches everything until the final literal .
Non-greedily matches everything after the ., which it captures.
For your specific case of removing a suffix, this is likely overkill, though.
I've got a ton of files as follows
audiofile_drums_1-ktpcwybsh5c.wav
soundsample_drums_2-fghlkjy57sa.wav
noise_snippet_guitar_5-mxjtgqta3o1.wav
louder_flute_9-mdlsiqpfj6c.wav
I want to remove everything between and including the "-" and the .wav file extension, to be left with
audiofile_drums_1.wav
soundsample_drums_2.wav
noise_snippet_guitar_5.wav
louder_flute_9.wav
I've tried to do delete everything following and including the character "-" using
rename 's/-.*//' *
Which gives me
audiofile_drums_1
soundsample_drums_2
noise_snippet_guitar_5
louder_flute_9
And for lack of finding an easy way to rename all the files again, adding .wav the extension, I am hoping there is a slicker way to do this in one nifty command in one stage instead of 2.
Any suggestions?
Thanks
You can use rename 's/-[^\.]*\.wav$/\.wav/' *
The first part -[^\.]*\.wav$ searchs for a - followed by n chars that are not . followed by .wav and the end of filename. The end of filename and .wav is not strictly needed but it helps avoid renaming files you don't want to rename.
The /\.wav/ preserves the extension.
Please not that rename is not a standard utility, and is part of perl, so rename may not be available on every linux system.
This works in my specific case, but should work for any file extension.
rename -n 's/-.*(?=\.wav$)//' *
The command looks for all characters after and inclusive of the - symbol in the filename, then, using a positive lookahead** (?=\.wav$) to search for the characters (the file extension in this case) at the end of the filename (denoted by $, and replaces them with no characters (removing them).
** NOTE: A positive look ahead is a zero width assertion.
It will affect the match but it will not be included
in the replacement. (The '.wav' part will not be
erased)
In this example (?=\.wav$) is the positive lookahead. The dollar sign $, as in regex, denotes at the end of the line, so perfect for a file extension.
I am trying to restrict a user from being able to write to .c files in a depot location. I found 2 ways to achieve this. Add
=write growth * -//depot/new_team/....c
or
=write growth * -//depot/new_team/.../*.c
to protect table. Are both of these correct? Does one have preference over other?
They are very similar but not identical.
//depot/new_team/....c
This selects all files that end in .c anywhere under //depot/new_team/. For example, it matches //depot/new_team/foo.c as well as //depot/new_team/dir/foo.c.
//depot/new_team/.../*.c
This selects all files that end in .c in subdirectories of //depot/new_team/. It matches //depot/new_team/dir/foo.c but not //depot/new_team/foo.c. In the case of //depot/new_team/foo.c, it is not a match because your pattern asks for a slash between ... and *.c, but //depot/new_team/foo.c doesn't have one.
I've compiled hundres of org-mode files in a specific directory.
Is there any way to search these files for specific keywords, or build agendas,
without loading them into Emacs, possibly using external search tools such as `ag'?
You can search them using Icicles. In Icicle minor mode, C-x C-f is bound to a multi-completion command that lets you match against the file name or the file content, or both. You can change the match patterns on the fly. Buffer *Completions* shows you the files that match.
And you can use progressive completion, combining any number of search patterns. Each pattern can itself be a regexp (or a substring), but it is a lot easier to combine several simple patterns than it is to come up with one complex pattern to DTRT. You can also negate patterns (obtain the complement of the match set).
You can visit any of the matching files that you like -- any number of them during the same command invocation. Or you can visit none of them if you like (C-g), and just use the command to locate those that match. You can use C-M-RET, C-M-down, etc. to get information about particular matching files (file type, permissions, size, last access time, creation time, etc.).
You can act on any number of them in some other way than visiting, using an alternate function that you specify: Just bind variable icicle-candidate-alt-action-fn to this function in a command you write that invokes icicle-find-file-of-content. Lots more features --- see Icicles - File-Name Input.
In Linux how do I use find and regular expressions or a similar way without writing a script to search for files with multiple "dots" but IGNORE extension.
For e.g search through the following files will only return the second file. In this example ".ext" is the extension.
testing1234hellothisisafile.ext
testing.1234.hello.this.is.a.file.ext
The solution should work with one or more dots in the file name (ignoring the extension dot). This should also work for any files i.e. with any file extension
Thanks in advance
So if I understand correctly, you want to get the filenames with at least two additional dots in the name. This would do:
$ find -regex ".*\.+[^.]*\.+[^.]*\.+.*"
./testing.1234.hello.this.is.a.file.ext
./testing1234.hellothisisafile.ext
$ find -regex ".*\.+[^.]*\.+[^.]*\.+[^.]*\.+.*"
./testing.1234.hello.this.is.a.file.ext
The key dot detecting part is \.+ (at least one dot), coupled with the separating anything (but a dot, but the previous part covers it already; a safety measure against greedy matching) [^.]*. Together they make the core part of the regex - we don't care what is before or after, just that somewhere there are three dots. Three since also the one from the current dir matters — if you'll be searching from elsewhere, remove one \.+[^.]* group:
$ find delme/ -regex ".*\.+[^.]*\.+[^.]*\.+[^.]*\.+.*"
delme/testing.1234.hello.this.is.a.file.ext
$ find delme/ -regex ".*\.+[^.]*\.+[^.]*\.+.*"
delme/testing.1234.hello.this.is.a.file.ext
In this case the result is the same, since the name contains a lot of dots, but the second regex is the correct one.