I'm using the following awk command to replace strings in a swift source file:
awk '
BEGIN { old=ARGV[1]; new=ARGV[2]; ARGV[1]=ARGV[2]=""; len=length(old) }
s=index($0,old) { $0 = substr($0,1,s-1) new substr($0,s+len) }
{ print }
' "$old" "$new" "$file" > ./temp
Trying not to edit commented out values. At a minimum, need to ignore lines that start with "//" but it seems possible to ignore inline comments (e.g. when the line is only partially commented like "MATCH // <- Ok" or "foo // MATCH <- Not Ok").
Something like...
s=index($0,old) && !($0 =~ "^//") { ... }
Sample Input:
old="\"Some \(value) with %# special \n characters\""
new="\"some_key\".localized"
file {contents}...
/// - Returns: "Some \(value) with %# special \n characters"
static let someValue = "Some \(value) with %# special \n characters" // <-- This should change
static let otherValue = "This line does NOT change" // "Some \(value) with %# special \n characters"
Expected Output:
/// - Returns: "Some \(value) with %# special \n characters"
static let someValue = "some_key".localized // <-- This should change
static let otherValue = "This line does NOT change" // "Some \(value) with %# special \n characters"
EDIT
Although #RavinderSingh13's answer did not match expected output, it was close and I used it to modify my command like so:
BEGIN { old=ARGV[1]; new=ARGV[2]; ARGV[1]=ARGV[2]=""; len=length(old) }
s=index($0,old) { if (!(match($0,/.*\/\//))) $0 = substr($0,1,s-1) new substr($0,s+len) }
{ print }' "$old" "$new" "$file"
This meets the original requirement, but ignores ANY line that has two slashes. This is problematic, because it doesn't support in line comments (e.g. the above command would not edit any of the sample input; unless the "// <-- This should change" comment is removed. If no one replies, I'll use this as the answer, but I'll wait a day or so in case someone posts a version of the command that meets all the requirements. Will accept that answer.
It would be something like this...
s=index($0,old) { if (!(match($0,/.*\/\//)) || (match($0,/"$old".*\/\//))) $0 = substr($0,1,s-1) new substr($0,s+len) }
Considering that you want skip all lines which start from // and also you want to print contents which comes before // for in between inline comments. Fair warning not tested since NO samples given.
awk '
BEGIN { old=ARGV[1]; new=ARGV[2]; ARGV[1]=ARGV[2]=""; len=length(old) }
/^\/\//{ next }
match($0,/.*\/\//){ $0 = substr($0,RSTART,RLENGTH-2) }
s=index($0,old) { $0 = substr($0,1,s-1) new substr($0,s+len) }
{ print }
' "$old" "$new" "$file" > ./temp
Above will neglect lines which are starting with // if you want to print them then do following.
awk '
BEGIN { old=ARGV[1]; new=ARGV[2]; ARGV[1]=ARGV[2]=""; len=length(old) }
/^\/\//{ print; next }
match($0,/.*\/\//){ $0 = substr($0,RSTART,RLENGTH-2) }
s=index($0,old) { $0 = substr($0,1,s-1) new substr($0,s+len) }
{ print }
' "$old" "$new" "$file" > ./temp
Only look for "old" in the part of each line before the start of any comment, e.g.:
awk '
BEGIN { old=ARGV[1]; new=ARGV[2]; ARGV[1]=ARGV[2]=""; len=length(old) }
{ preCmt = $0; sub("//.*","", preCmt) }
s=index(preCmt,old) { $0 = substr($0,1,s-1) new substr($0,s+len) }
{ print }
' "$old" "$new" file
/// - Returns: "Some \(value) with %# special \n characters"
static let someValue = "some_key".localized // <-- This should change
static let otherValue = "This line does NOT change" // "Some \(value) with %# special \n characters
Related
I'm trying to delete a section elasticsearch { * } from a configuration file due to lack other options.
output {
if [env] {
if [containerimage] and [containerimage] != "apache" {
file {
path => "/var/log/logstash/logs/%{[env]}/%{file}-%{+YYYY-MM-dd}"
}
elasticsearch {
hosts => ["{{elasticsearch/host}}:{{elasticsearch/port}}"]
template_overwrite => true
}
}
}
}
I tried to reverse the sed command found on stackoverflow but it deletes ending } from configuration files too.
[root#indexer conf.d]# sed '/{/{:1; /}/!{N; b1}; /elasticsearch/!p}; d' example
output {
if [env] {
if [containerimage] and [containerimage] != "apache" {
file {
path => "/var/log/logstash/logs/%{[env]}/%{file}-%{+YYYY-MM-dd}"
It may be due to }} in to cfg that must be there. Any ideas to overcome this problem? Thanks in advance
Edit:
some other experiment:
sed '/elasticsearch {/{:1; /}/!{N; b1} }; /elasticsearch/!p; d' example
output {
if [env] {
if [containerimage] and [containerimage] != "apache" {
file {
path => "/var/log/logstash/logs/%{[env]}/%{file}-%{+YYYY-MM-dd}"
}
template_overwrite => true
}
}
}
}
But leaves template_overwrite and some closing braces.
This might work for you (GNU sed):
sed '/^\s*elasticsearch {$/{:a;N;/^\s*}$/M!ba;d}' file
Gather up the lines beginning elasticsearch { and ending } and delete them.
N.B. This uses the M flag for a multiline match for the end condition which is GNU sed specific. An alternative:
sed -n '/^\s*elasticsearch {$/{:a;n;/^\s*}$/!ba;d};p' file
Here's one in awk:
awk '
BEGIN {
RS="^$" # read in the whole file
c=1 # brace counter
}
{
match($0,/\n? *elasticsearch \{/) # find the start of string to remove
print substr($0,1,RSTART-1) # RUNNING OUT OF BATTERY
$0=substr($0,RSTART+RLENGTH)
while(c>0) {
match($0,/(\{|\} *\n*)/)
if(substr($0,RSTART,1)=="{")
c++
else
c--
$0=substr($0,RSTART+RLENGTH)
}
print
}' file
Output:
output {
if [env] {
if [containerimage] and [containerimage] != "apache" {
file {
path => "/var/log/logstash/logs/%{[env]}/%{file}-%{+YYYY-MM-dd}"
}
}
}
}
Only tested with provided data.
Is this all you're trying to do?
$ sed '/elasticsearch[[:space:]]*{/,/^[[:space:]]*}/d' file
output {
if [env] {
if [containerimage] and [containerimage] != "apache" {
file {
path => "/var/log/logstash/logs/%{[env]}/%{file}-%{+YYYY-MM-dd}"
}
}
}
}
The above will work with any POSIX sed. If that's not all you need then please edit your question to show a more truly representative example so we can help you. FWIW I wouldn't really do the above as it's not extensible if/when your requirements vary slightly, I'd do this instead:
$ awk '/elasticsearch[[:space:]]*{/{f=1} !f; /^[[:space:]]*}/{f=0}' file
output {
if [env] {
if [containerimage] and [containerimage] != "apache" {
file {
path => "/var/log/logstash/logs/%{[env]}/%{file}-%{+YYYY-MM-dd}"
}
}
}
}
Below is the example of my file,
signal {
{
ab
cd
}
"m_1_clk" {
P {
'0ns' D;
'25ns' U;
'65ns' D;
}
}
"m_0_clk" {
P {
'0ns' D;
'25ns' U;
'65ns' D;
}
}
"o_[9]" {
Data S Mk {
Active Up;
}
}
"m_0_clk" {
Data S Mk {
Active Up;
}
}
"m_1_clk" {
Data S Mk {
Active Up;
}
}
}
I am expecting the output from above file to be:
signal {
{
ab
cd
}
"o_[9]" {
Data S Mk {
Active Up;
}
}
}
Hi,
Above is the example of my file
I would like to delete pattern which matches the next pattern which is calling in the next line.
Trying to search the specific pattern for deleting the lines which it should not be present in my file.
Need to search the specific pattern with new pattern in the next line. because first line is calling in multiple loops. so should grep specific pattern of all the content.
I tried using the below command in tcl its not working. could anyone help me on this,
below is the sed command used in tcl
exec /bin/sed -e {s/\m\(.*\)clk" {\.*\n\.*Data\.*//} -i file
exec /bin/sed -e {s/\m\(.*\)clk" {\.*\n\.*P {\.*//} -i file
Could you please try following and let me know if this helps you.(Considering that your actual Input_file is same as shown sample file)
awk -v line_number=$(cat Input_file | wc -l) '/signal {/ || /"o_\[9\]" {/ || FNR==line_number{flag=1}; /^$/{flag=""} flag' Input_file
Explanation: Adding explanation for code too now as follows:
awk -v line_number=$(cat Input_file | wc -l) ' ##Creating variable named line_number in awk script whose value is number of lines of Input_file.
/signal {/ || /"o_\[9\]" {/ || FNR==line_number{ ##checking condition here if a line contains strings either signal { OR "o_\[9\]" { then do following:
flag=1} ##Setting variable named flag here and setting its value to 1 here.
/^$/{ ##Checking condition here if a line is NULL or BLANK then do following:
flag=""} ##Nullifying the variable flag here.
flag ##awk works on method of condition then actions, so checking if variable flag value is NOT NULL here and not mentioning any action here so by default peint of current line will happen here.
' Input_file ##Metioning the Input_file name here.
Solution with a context-sensitive parser:
use Marpa::R2 qw();
my $input = <<'INPUT';
signal {
{
ab
cd
}
"m_1_clk" {
P {
'0ns' D;
'25ns' U;
'65ns' D;
}
}
"m_0_clk" {
P {
'0ns' D;
'25ns' U;
'65ns' D;
}
}
"o_[9]" {
Data S Mk {
Active Up;
}
}
"m_0_clk" {
Data S Mk {
Active Up;
}
}
"m_1_clk" {
Data S Mk {
Active Up;
}
}
}
INPUT
my $grammar = Marpa::R2::Scanless::G->new({
bless_package => 'Foo',
source => \<<'GRAMMAR',
:default ::= action => [values] bless => ::lhs
lexeme default = action => [ value ] bless => ::name latm => 1
:start ::= blocks
blocks ::= block+
block ::= optionalname [{] contentblocks [}] optionalws
optionalname ::= name | epsilon
contentblocks ::= contentorblock+
contentorblock ::= content | block
name ~ [a-zA-Z0-9_"\x{5b}\x{5d} ]+
content ~ [a-zA-Z0-9;'\s]*
optionalws ~ [\s]*
epsilon ::=
GRAMMAR
});
my $parser = Marpa::R2::Scanless::R->new({grammar => $grammar});
$parser->read(\$input);
my $output;
deleteblocks($parser->value->$*);
print $output;
sub deleteblocks {
my ($v) = #_;
return if ref $v eq 'Foo::block' and $v->[0][0]
and $v->[0][0][0] !~ /signal|"o_\[9\]"/;
if (ref $v) {
deleteblocks($_) for $v->#*;
} else {
$output .= $v || '';
}
}
Output is:
signal {
{
ab
cd
}
"o_[9]" {
Data S Mk {
Active Up;
}
}
}
It is possible to use a string as an operator?
my $ip = "10 > 0.2 && 5 < 1";
if($ip)
{
print "Hello\n\n";
}
else
{
print "wrong\n";
}
How to consider the string > && < as an operator?
A non-empty string will always evaluate to true if you use it like this. What you want to do is to evaluate the content of the string as code, and perl provides the eval-statement for exactly this purpose:
my $ip = "10 > 0.2 && 5 < 1";
if( eval($ip) )
{
print "Hello \n\n";
}
else
{
print "wrong\n";
}
This will give the expected output "wrong".
I'm writing a description of R syntax, and I'd like to include some statements that include syntax errors, e.g.
if (n >= 2)
{
# if TRUE
}
else
{
# if FALSE
}
(This is a syntax error at top level because the if is complete before the else is read.) I'm trying to put this into a knitr document, but
even with error=TRUE it fails, because that option only affects run-time errors, not syntax errors. Is there some reasonable way to get this to display what would be shown if I entered it at the console? I.e.
I'd like it to display something like
if (n >= 2)
{
# if TRUE
}
else
Error: unexpected 'else' in "else"
{
# if FALSE
}
Here's a function that does part of what I want: it reproduces the output from a syntax error, but it doesn't do all the markup that knitr would do, so the formatting is wrong.
parse_with_error <- function(text) {
reportError <- function(e) {
msg <- conditionMessage(e)
line <- as.numeric(sub("^text:([[:digit:]]*):.*", "\\1", msg))
col <- as.numeric(sub("^text:[[:digit:]]*:([[:digit:]]*):.*", "\\1", msg))
cat(text[1:line], sep="\n")
if (col > 1)
cat(paste(rep(" ", col-1), collapse=""))
cat("^\n")
err <- sub("^text:[[:digit:]]*:[[:digit:]]*: ([^[:cntrl:]]*)\n.*", "\\1", msg)
parseData <- getParseData(sf)
lastToken <- parseData[nrow(parseData), "text"]
cat(paste0("Error: ", err, ' in "', lastToken, '"'), "\n")
}
text <- unlist(strsplit(text, "\n"))
sf <- srcfile("text")
tryCatch(parse(text = text, keep.source = TRUE, srcfile=sf),
error = reportError)
}
This shows how it would be used:
parse_with_error(
"if (TRUE) {
# do TRUE
}
else {
# do FALSE
}")
You can use a separate R session to evaluate the code, e.g.
```{r, engine='Rscript', error=TRUE}
if (TRUE)
{
# if TRUE
}
else
{
# if FALSE
}
```
How do i get all of the lines of "$dblink is down" into one $l_msg string?
Ideally I would like to get the error returned by oracle on failure and I cannot see a way to solve this.
my $dblinks = $l_dbh->selectcol_arrayref("select dbname from db_link");
for my $dblink (#$dblinks) {
my $l_results = eval {
my ($l_erg) = $l_dbh->selectrow_array("SELECT dummy||'OK' "
. $l_dbh->quote_identifier($dblink, undef, "dual") );
$l_erg;
};
while (#l_row = $l_results->fetchrow_array) {
$l_erg=$l_row[0];
if ($l_results !~ /XOK/) {
#l_errstr=();
l_msg="$dblink is down with #l_errstr"
# dblink45667 is down with ORA-12154"
} else {
say "$dblink is is up";
}
}
}
How about concatenating them to a variable outside of the loop:
my $dblinks = $l_dbh->selectcol_arrayref("select dbname from db_link");
my $l_msg = '';
for my $dblink (#$dblinks) {
my $l_results = eval {
my ($l_erg) = $l_dbh->selectrow_array("SELECT dummy||'OK' "
. $l_dbh->quote_identifier($dblink, undef, "dual") );
$l_erg;
};
while (#l_row = $l_results->fetchrow_array) {
$l_erg=$l_row[0];
if ($l_results !~ /XOK/) {
#l_errstr=();
l_msg .= "$dblink is down with #l_errstr"
# dblink45667 is down with ORA-12154"
} else {
say "$dblink is is up";
}
}
}