I have a csh script, my goal is to read an ini config file with perl module Config::Simple. I want to execute my perl command and assign the result to one variable.
perl -MConfig::Simple -e '$cfg = new Config::Simple("../config.ini"); $myvar = $cfg->param("myvar");'
What is the syntax ?
Receive the script's return value into a variable? I con't know the csh syntax, but in bash that is:
myvar=`perl ....`;
But if you wanted to set several variables, not sure.
For setting several variables you could have the perl script print csh syntax that the shell would evaluate.
I don't know csh but in bash it should be done like
#!/bin/sh
eval `perl -E 'say "FOO=123"; say "BAR=456"'`
echo "FOO is $FOO"
Command substitution in csh looks like this:
#!/bin/csh
set VAR=`perl -E 'say q(hello world)'`
echo ${VAR}
And, as an aside, I hope your using a descendent of csh like tcsh. The original csh implementation is a brain-dead mangled shell. This classic paper describes why.
I had a similar requirement, where I was using python instead of perl.
my python script was producing 3 output strings and the values were needed to be set in csh as variable.
Here's a solution.. hope it will help!
Inside Python:
I was using three variables : x , y and z I had only
one print statement in python which printed: x,y,z
Inside CSH:
set py_opt = `./my_python_script`
set csh_x = `echo $py_opt | sed 's/,/ /g' | awk '{print $1}'`
set csh_y = `echo $py_opt | sed 's/,/ /g' | awk '{print $2}'`
set csh_z = `echo $py_opt | sed 's/,/ /g' | awk '{print $3}'`
Related
I am trying to replace string with a new string containing $(dollar) sign in a existing file.
I have used below (regex) line in my code but I am not able get the expected result. Please suggest the solution.
system("perl -pi -e \"s/length\\s+.*/length [index $pkt_len]/g if /^\\s*set_value\\s+length/\" $filename")
The way to find the solution is during debug you should print out the line of the system call and test it "by hand" if it works as expected in the shell.
My guess is that
system("perl -pi -e 's/length\\s+.*/length [index \\\$pkt_len]/g if /^\\s*set_value\\s+length/' $filename")
is a solution.
You need 7 backslashes (!):
system("echo a | perl -pe \"s/a/\\\\\\\$foo/\"");
Output:
$foo
First "echo a | perl -pe \"s/a/\\\\\\\$foo/\"" is interpreted by perl which reduces the string to echo a | perl -pe "s/a/\\\$foo/"
Then it is parsed by the shell sh to give : echo a | perl -pe s/a/\$foo/
Finally, it is parsed by perl a second time to give the output $foo.
I have the following sed command:
sed -i -E "s/\{\{(.*)\}\}/$(echo "$\1")/g" test.conf
In test.conf, I have this:
this is a {{TEST}}
and this is an {{ANSWER}} here.
And I have the follow environment variables set:
export TEST=1234
export ANSWER=5678
When I run the sed command, I end up with this result:
this is a $TEST
and this is an $ANSWER here.
I want 1234 and 5678 there respectively. Is there a reason the echo command is interpreting things literally?
Backreferences are used internally by a single sed command. The echo has no idea about sed backreferences and would have been invoked by the shell before the sed command has even run so the $(echo "$\1") is outputing $\1 so
sed -i -E "s/\{\{(.*)\}\}/$(echo "$\1")/g" test.conf
is really:
sed -i -E "s/\{\{(.*)\}\}/$\1/g" test.conf
hence the output you are seeing.
Anyway, sed is for simple subsitutions on individual lines, for anything else you should be using awk:
$ export TEST=1234 ANSWER=5678
$ awk 'match($0,/(.*)\{\{(.*)\}\}(.*)/,a){$0=a[1] ENVIRON[a[2]] a[3]} 1' file
this is a 1234
and this is an 5678 here.
The above uses GNU awk for the 3rd arg to match(), with other awks it'd be:
$ awk 'match($0,/\{\{(.*)\}\}/){$0=substr($0,1,RSTART-1) ENVIRON[substr($0,RSTART+2,RLENGTH-4)] substr($0,RSTART+RLENGTH)} 1' file
this is a 1234
and this is an 5678 here.
If anyone suggests running eval or similar on the sed output - don't do it (google eval is evil and friends), just use the awk command above for simple string operations.
You can use perl which conveniently has a %ENV hash variable, see perldoc for more info
perl -pe 's/\{\{(.*)\}\}/$ENV{$1}/' test.conf
When i execute the below command in command prompt it works fine. but when i include the same in perl script, it shows the whole process name.
ps -ef | grep truecontrol | awk '{print$2}'
returns
4567
3456
When I execute it throught perl, it shows the whole process details. I want to assign it to a variable array and work on it. Let me know how to do it?
my $process_chk_command = `ps -ef | grep truecontrol | awk '{print$2}'`;
print($process_chk_command);
root 9902 9890 0 05:50 ? 00:00:03 /opt/abc/jre/bin/java -DTCFTP=1 -d64 -Xms16m -Xmx64m -Djava.library.path=/opt/abc/server/ext/wrapper/lib -cla
perl's backticks and qx// interpolate variables, so when you write:
my $process_chk_command = `ps -ef | grep truecontrol | awk '{print $2}'`;
perl interpolates the special variable $2. In your case, $2 is not set, and thus expands to the empty string, so the awk command is simply {print}.
You could escape the dollar sign (`ps ... | awk '{print \$2}'`) to avoid this.
(As an aside, I'd recommend grep [t]ruecontrol to prevent grep from matching its own process table entry, or that of its parent shell which constructs the pipeline. sh aficionados with a POSIX bent might additionally suggest `ps -eo pid,comm,args | awk '/[t]ruecontrol/{print \$1}'`.)
Try using pgrep
my $process_chk_command = `pgrep truecontrol`;
my $process_chk_command = `ps -ef | grep truecontrol`;
my (undef,$pid) = split(' ', $process_chk_command, -1);
ps, there's a perl utility that converts awk scripts to perl: a2p
True to Perl's motto, another way:
my $pcc=`killall -s truecontrol`;
my (undef,undef,$pid)=split(' ',$pcc);
print $pid;
I have a plaintext file containing multiple instances of the pattern $$DATABASE_*$$ and the asterisk could be any string of characters. I'd like to replace the entire instance with whatever is in the asterisk portion, but lowercase.
Here is a test file:
$$DATABASE_GIBSON$$
test me $$DATABASE_GIBSON$$ test me
$$DATABASE_GIBSON$$ test $$DATABASE_GIBSON$$ test
$$DATABASE_GIBSON$$ $$DATABASE_GIBSON$$$$DATABASE_GIBSON$$
Here is the desired output:
gibson
test me gibson test me
gibson test gibson test
gibson gibsongibson
How do I do this with sed/awk/tr/perl?
Here's the perl version I ended up using.
perl -p -i.bak -e 's/\$\$DATABASE_(.*?)\$\$/lc($1)/eg' inputFile
Unfortunately there's no easy, foolproof way with awk, but here's one approach:
$ cat tst.awk
{
gsub(/[$][$]/,"\n")
head = ""
tail = $0
while ( match(tail, "\nDATABASE_[^\n]+\n") ) {
head = head substr(tail,1,RSTART-1)
trgt = substr(tail,RSTART,RLENGTH)
tail = substr(tail,RSTART+RLENGTH)
gsub(/\n(DATABASE_)?/,"",trgt)
head = head tolower(trgt)
}
$0 = head tail
gsub("\n","$$")
print
}
$ cat file
The quick brown $$DATABASE_FOX$$ jumped over the lazy $$DATABASE_DOG$$s back.
The grey $$DATABASE_SQUIRREL$$ ate $$DATABASE_NUT$$s under a $$DATABASE_TREE$$.
Put a dollar $$DATABASE_DOL$LAR$$ in the $$ string.
$ awk -f tst.awk file
The quick brown fox jumped over the lazy dogs back.
The grey squirrel ate nuts under a tree.
Put a dollar dol$lar in the $$ string.
Note the trick of converting $$ to a newline char so we can negate that char in the match(RE), without that (i.e. if we used ".+" instead of "[^\n]+") then due to greedy RE matching if the same pattern appeared twice on one input line the matching string would extend from the start of the first pattern to the end of the second pattern.
This one works with complicated examples.
perl -ple 's/\$\$DATABASE_(.*?)\$\$/lc($1)/eg' filename.txt
And for simpler examples :
echo '$$DATABASE_GIBSON$$' | sed 's#$$DATABASE_\(.*\)\$\$#\L\1#'
in sed, \L means lower case (\E to stop if needed)
Using awk alone:
> echo '$$DATABASE_AWESOME$$' | awk '{sub(/.*_/,"");sub(/\$\$$/,"");print tolower($0);}'
awesome
Note that I'm in FreeBSD, so this is not GNU awk.
But this can be done using bash alone:
[ghoti#pc ~]$ foo='$$DATABASE_AWESOME$$'
[ghoti#pc ~]$ foo=${foo##*_}
[ghoti#pc ~]$ foo=${foo%\$\$}
[ghoti#pc ~]$ foo=${foo,,}
[ghoti#pc ~]$ echo $foo
awesome
Of the above substitutions, all except the last one (${foo,,}) will work in standard Bourne shell. If you don't have bash, you can instead do use tr for this step:
$ echo $foo
AWESOME
$ foo=$(echo "$foo" | tr '[:upper:]' '[:lower:]')
$ echo $foo
awesome
$
UPDATE:
Per comments, it seems that what the OP really wants is to strip the substring out of any text in which it is included -- that is, our solutions need to account for the possibility of leading or trailing spaces, before or after the string he provided in his question.
> echo 'foo $$DATABASE_KITTENS$$ bar' | sed -nE '/\$\$[^$]+\$\$/{;s/.*\$\$DATABASE_//;s/\$\$.*//;p;}' | tr '[:upper:]' '[:lower:]'
kittens
And if you happen to have pcregrep on your path (from the devel/pcre FreeBSD port), you can use that instead, with lookaheads:
> echo 'foo $$DATABASE_KITTENS$$ bar' | pcregrep -o '(?!\$\$DATABASE_)[A-Z]+(?=\$\$)' | tr '[:upper:]' '[:lower:]'
kittens
(For Linux users reading this: this is equivalent to using grep -P.)
And in pure bash:
$ shopt -s extglob
$ foo='foo $$DATABASE_KITTENS$$ bar'
$ foo=${foo##*(?)\$\$DATABASE_}
$ foo=${foo%%\$\$*(?)}
$ foo=${foo,,}
$ echo $foo
kittens
Note that NONE of these three updated solutions will handle situations where multiple tagged database names exist in the same line of input. That's not stated as a requirement in the question either, but I'm just sayin'....
You can do this in a pretty foolproof way with the supercool command cut :)
echo '$$DATABASE_AWESOME$$' | cut -d'$' -f3 | cut -d_ -f2 | tr 'A-Z' 'a-z'
This might work for you (GNU sed):
sed 's/$\$/\n/g;s/\nDATABASE_\([^\n]*\)\n/\L\1/g;s/\n/$$/g' file
Here is the shortest (GNU) awk solution I could come up with that does everything requested by the OP:
awk -vRS='[$][$]DATABASE_([^$]+[$])+[$]' '{ORS=tolower(substr(RT,12,length(RT)-13))}1'
Even if the string indicated with the asterix (*) contained one or more single Dollar signs ($) and/or linebreaks this soultion should still work.
awk '{gsub(/\$\$DATABASE_GIBSON\$\$/,"gibson")}1' file
gibson
test me gibson test me
gibson test gibson test
gibson gibsongibson
echo $$DATABASE_WOOLY$$ | awk '{print tolower($0)}'
awk will take what ever input, in this case the first agurment, and use the tolower function and return the results.
For your bash script you can do something like this and use the variable DBLOWER
DBLOWER=$(echo $$DATABASE_WOOLY$$ | awk '{print tolower($0)}');
This question already has answers here:
sed substitution with Bash variables
(6 answers)
Closed 24 days ago.
The sed command works as expected at the command prompt, but does not work in a shell script.
new_db_name=`echo "$new_db_name" | sed 's/$replace_string/$replace_with/'`
Why is that, and how can I fix it?
Use double quotes for the sed expression.
new_db_name=$(echo "$new_db_name" | sed "s/$replace_string/$replace_with/")
If you use bash, this should work:
new_db_name=${new_db_name/$replace_string/$replace_with}
This worked for me in using env arguments.
export a=foo
export b=bar
echo a/b | sed 's/a/'$b'/'
bar/b
Guys: I used the following to pass bash variables to a function in a bash script using sed. I.e., I passed bash variables to a sed command.
#!/bin/bash
function solveOffendingKey(){
echo "We will delete the offending key in file: $2, in line: $1"
sleep 5
eval "sed -i '$1d' $2"
}
line='4'
file=~/ivan/known_hosts
solveOffendingKey $number $file
Kind regards!
depending on how your variables are initialized, you are better off using brackets:
new_db_name=`echo "$new_db_name" | sed "s/${replace_string}`/${replace_with}/"
Maybe I'm missing something but new_db_name=echo "$new_db_name" doesn't make sense here. $new_db_name is empty so you're echoing a null result, and then the output of the sed command. To capture stdout as a variable, backticks aren't recommended anymore. Capture output surrounded by $().
new_db_name=$(sed "s/${replace_string}/${replace_with}/")
Take the following example:
replace_string="replace_me"
replace_with=$(cat replace_file.txt | grep "replacement_line:" | awk FS" '{print $1}')
Where replace_file.txt could look something like:
old_string: something_old
I like cats
replacement_line: "shiny_new_db"
Just having the variable in the sed expresion $replace_with won't work. bash doesn't have enough context to escape the variable expression. ${replace_with} tells bash to explicitly use the contents of the command issued by the variable.