I want to parse a version number like 2019.10-devel-97 or 2019.10.1 into mayor, minor and patch version.
The patch level is optional.
I came up with the following regex:
sed -E 's/([0-9]+).([0-9]+).?([0-9]+)?.*/VERSION_MACRO(\1, \2, \3)/'
For 2019.10.1 this correctly prints VERSION_MACRO(2019, 10, 1) but if there is no patch level, I will get VERSION_MACRO(2019, 10, ).
Is there a way to set the default value of the capture group to 0 instead of blank space?
There is no direct support for defaults, but you can add a statement to replace , ) with , 0).
sed -E -e 's/([0-9]+).([0-9]+).?([0-9]+)?.*/VERSION_MACRO(\1, \2, \3)/' \
-e 's/, \)/, 0)/' file
sed is a bit of a write-only language, though, Perhaps you are better off using a higher-level language for any nontrivial text processing.
awk -F . '{ OFS = ", ";
print "VERSION_MACRO(" $1, $2, 0+$3 ")"}' file
Related
My env
OSX 10.11.6
zsh 5.0.8 (x86_64-apple-darwin15.0)
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin15)
Mono C# compiler version 4.0.5.0
test.cs
class Test {
public static void Main() {
System.Console.WriteLine("hello, world");
}
}
test.sh
#! /bin/bash
mcs -recurse:*.cs
I can use ./test.sh to compile test.cs
but if I change test.sh to
#! /bin/zsh
mcs -recurse:*.cs
error shows
./test.sh:3: no matches found: -recurse:*.cs
So, Why I can not use zsh?
zsh is attempting to expand the * in that word as a file glob, failing, and throwing an error.
bash does the same thing but, by default, it just ignores the globbing failure and keeps the word intact (so mcs sees the argument it expects).
Add shopt -s failglob to the top of the script (for bash) and it will fail also.
Quote the * in the argument to mcs to avoid this.
mcs -recurse:'*.cs'
Because the string -recurse:*.cs contains an unquoted *, most shells will attempt to treat it as a glob pattern and expand it to one or more matching file names.
The default behavior in zsh is to treat a pattern that has no matches as an error, rather than treating the pattern as a literal string. The same behavior can be seen in bash if you enable the failglob option.
$ echo foo*
foo*
$ shopt -s failglob
$ echo foo*
bash: no match: foo*
In zsh, either quote the pattern:
#! /bin/zsh
mcs -recurse:"*.cs"
turn off the NOMATCH option,
#! /bin/zsh
setopt NO_NOMATCH
mcs -recurse:*.cs
or use the zsh command modifier:
#! /bin/zsh
noglob mcs -recurse:*.cs
In your command mcs -recurse:*.cs, the * is intended to be passed to mcs as a literal part of the argument, but it is also meaningful to all common Unix shells (bash, zsh, tcsh, and others) as a wildcard for pathname expansion. As such, your command would probably surprise you if there were a file named -recurse:oops.cs in the working directory.
The difference arises in the shells' default behavior when no file matches the given pattern. By default, bash falls back to guessing that you meant the * to be a literal, which is in fact what you meant. zsh, on the other hand, exhibits the more traditional behavior of failing on account of the failure to match the pattern. bash can be induced to exhibit that behavior, too, by turning on its failglob option.
The best solution is to resolve the ambiguity by quoting the argument, or at least escaping the * in it. Both bash and zsh should handle this version fine without any special options:
mcs -recurse:\*.cs
I have a text file where I wish to search if a set of lines exists and update/overwrite them or if the set of lines does not exists, add them.
Here is the text file.
#
# Virtual Hosts
#
# If you want to maintain multiple domains/hostnames on your
# machine you can setup VirtualHost containers for them. Most configurations
# use only name-based virtual hosts so the server doesn't need to worry about
# IP addresses. This is indicated by the asterisks in the directives below.
#
# Please see the documentation at
# <URL:http://httpd.apache.org/docs/2.2/vhosts/>
# for further details before you try to setup virtual hosts.
#
# You may use the command line option '-S' to verify your virtual host
# configuration.
#
# Use name-based virtual hosting.
#
##NameVirtualHost *:80
#
# VirtualHost example:
# Almost any Apache directive may go into a VirtualHost container.
# The first VirtualHost section is used for all requests that do not
# match a ServerName or ServerAlias in any <VirtualHost> block.
#
##<VirtualHost *:80>
##ServerAdmin postmaster#dummy-host.localhost
##DocumentRoot "C:/xampp/htdocs/dummy-host.localhost"
##ServerName dummy-host.localhost
##ServerAlias www.dummy-host.localhost
##ErrorLog "logs/dummy-host.localhost-error.log"
##CustomLog "logs/dummy-host.localhost-access.log" combined
##</VirtualHost>
##<VirtualHost *:80>
##ServerAdmin postmaster#dummy-host2.localhost
##DocumentRoot "C:/xampp/htdocs/dummy-host2.localhost"
##ServerName dummy-host2.localhost
##ServerAlias www.dummy-host2.localhost
##ErrorLog "logs/dummy-host2.localhost-error.log"
##CustomLog "logs/dummy-host2.localhost-access.log" combined
##</VirtualHost>
<VirtualHost *:80>
ServerAdmin postmaster#dummy-host2.localhost
DocumentRoot "C:/xampp/htdocs/dummy-host2.localhost"
ServerName dummy-host2.localhost
ServerAlias www.dummy-host2.localhost
#ErrorLog "logs/dummy-host2.localhost-error.log"
CustomLog "logs/dummy-host2.localhost-access.log" combined
</VirtualHost>
Here is the skeleton code. I first open the text file, and read it to the end so that I can use the Regex class. (I chose this because the code looks cleaner and concise rather than doing it the C way - looping). But it isn't that simple because I need to check first a set of lines.
StreamReader reader = new StreamReader(path);
string content = reader.ReadToEnd();
reader.Close();
// Replace the strings using Regex replace method
StreamWriter writer = new StreamWriter(path);
writer.Write(content);
writer.Close();
Given a port number, I appended it to this pattern
string virtualHost = "<VirtualHost *:" + cls_globalvariables.portNumber + ">";
And I used
Match match = Regex.Match(content, virtualHost);
to find the index of the search pattern. I also had to find the index of its closing tag and replace them with an updated version of those lines. I have no problems of searching the ending line but I do have a problem of distinguishing the commented from uncommented lines.
Regex.Match returns the first occurrence of the search pattern which is the commented line. What I wanted to do was to search patterns without comments but how do I do that? I began thinking in C schemes such as looping character by character backwards and forwards starting from the match.Index until I detect a delimiter of "\r\n". Is there an efficient C# way to solve this?
You can either do it the way Jesse suggests, or if you want to stick to Regex, just put ^ at the start of your regex and set RegexOptions.Multiline.
Multiline mode. Changes the meaning of ^ and $ so they match at the beginning and end, respectively, of any line, and not just the beginning and end of the entire string. For more information, see the "Multiline Mode" section in the Regular Expression Options topic.
I have a question about using Sox. I need to mix many audio files and every file has it's own specific time when it should be added. I'm using piping and everything goes fine until I need to grab files with absolute paths with spaces in folder names. In this case I need to use double quotes twice (in path and to allocate piping). Here's example:
-m "initial.wav" "|sox "path with spaces\file1.mp3" -p pad 8.52 0" "|sox "another path with spaces\file2.mp3" -p pad 19.07 0" "|sox "file3.mp3" -p pad 36.52 0" "output.mp3"
And of course these quotes around file paths ruin command.
How can I fix this? Maybe it's possible to use single quotes somehow or maybe I'm missing something obvious...
Will may be useful to add that I'm runing sox from C# app, thus everything happens in Windows.
Usually, it is possible to escape the inner double quotes somehow. (Most?) *nix shells use the backslash for that purpose, i.e. you would write ... "|sox \"path with spaces/file1.mp3\" ...". Of course, Windows uses the backslash for different purposes (delimiting path components), so there may be a slightly different way to escape quotes.
I need to create a console application to print some help messages.I have done that but it does not show the results in the default tabular format in console like,
c:\Users\>dir /?
Displays a list of files and subdirectories in a directory.
DIR [drive:][path][filename] [/A[[:]attributes]] [/B] [/C] [/D] [/L] [/N]
[/O[[:]sortorder]] [/P] [/Q] [/R] [/S] [/T[[:]timefield]] [/W] [/X] [/4]
[drive:][path][filename]
Specifies drive, directory, and/or files to list.
/A Displays files with specified attributes.
attributes D Directories R Read-only files
H Hidden files A Files ready for archiving
S System files I Not content indexed files
L Reparse Points - Prefix meaning not
/B Uses bare format (no heading information or summary).
/C Display the thousand separator in file sizes. This is the
default. Use /-C to disable display of separator.
/D Same as wide but files are list sorted by column.
/L Uses lowercase.
/N New long list format where filenames are on the far right.
/O List by files in sorted order.
sortorder N By name (alphabetic) S By size (smallest first)
E By extension (alphabetic) D By date/time (oldest first)
G Group directories first - Prefix to reverse order
/P Pauses after each screenful of information.
Do i need to use escape sequences or is there any inbuilt function to display like this.I googled it.But unable to find solution can any one help:)?
You probably want to use Composite Formatting for this.
In this very specific case, simply put the content in a text file, and write to the console stream the content of the text file.
I would put the text file as a resource to simplify the deployment.
You should have to use #-quoted string literal.
string help = #"
Usage of #-quoted literal:
1. Escape sequences are not processed
2. To include double quotes then ""double it""
";
Console.WriteLine(help);
Just simply use spaces to format the output.
Console.WriteLine("DIR [drive:][path][filename] [/A[[:]attributes]]");
Console.WriteLine(" [/O[[:]sortorder]] [/P] [/Q] [/R] [/S] [/T[[:]timefield]]");
I have a string with multiple MAC addresses. How do I match all MACs except 00:00:00:00:00:00?
The regex I use to match a MAC:
((?:[0-9a-f]{2}[:-]){5}[0-9a-f]{2})
Frankly I'd recommend doing it in two parts. First fetch all the individual addresses using your regex, and then simply remove any zeroed addresses from the list. This is...
Most likely less computationally expensive, and
Far easier to read and maintain than a massive kludge of a regular expression.
This is the pattern you would need to do that:
(?!(?:00[:-]){5}00)((?:[0-9a-f]{2}[:-]){5}[0-9a-f]{2})
Edit - an answer to #trev's "how could you do this?"
use strict; use warnings;
my #samps = (
'MATCH_ME mac1=11:22:33:44:55:66 mac2=00:11:22:33:44:55',
'MATCH_ME mac1=00:00:00:00:00:00 mac2=00:11:22:33:44:55',
'MATCH_ME mac1=11:22:33:44:55:66 mac2=00:00:00:00:00:00',
'MATCH_ME mac1=00:00:00:00:00:00 mac2=00:00:00:00:00:00',
);
for (#samps) {
if ( /(MATCH_ME)\s*
mac1=
( (?!(?:00[:-]){5}00)
(?:[0-9a-f]{2}[:-]){5}[0-9a-f]{2}
|
)
.*?
mac2=
( (?!(?:00[:-]){5}00)
(?:[0-9a-f]{2}[:-]){5}[0-9a-f]{2}
|
)
/x )
{
print "'$1'\n";
print "'$2'\n";
print "'$3'\n",'-'x20,"\n";
}
}
output
'MATCH_ME'
'11:22:33:44:55:66'
'00:11:22:33:44:55'
--------------------
'MATCH_ME'
''
'00:11:22:33:44:55'
--------------------
'MATCH_ME'
'11:22:33:44:55:66'
''
--------------------
'MATCH_ME'
''
''