At the shell, I enter a single-quote and then carriage return and then a series of lines and then another single-quote:
root#aim:/root > '
> #stat = lstat($ARGV[0]);
> if (!#stat) {
if (#stat = lstat($ARGV[0]);) {
> print "nil\n";
> exit 0;
> }
> '
However, if you notice the interpreted output from the shell:
bash:
#stat = lstat($ARGV[0]);
if (#stat = lstat($ARGV[0]);) {
print "nil\n";
exit 0;
}
: command not found
root#aim:/root > uname -a
IRIX64 aim 6.5 04091957 IP27
root#aim:/root > echo $0
-bash
root#aim:/root >
You notice that !#stat gets converted to #stat = lstat($ARGV[0]);
How should the following shell program be written so that the perl program within it gets interpreted literally?
tramp_perl_file_attributes () {
\perl -e '
#stat = lstat($ARGV[0]);
if (!#stat) {
print "nil\n";
exit 0;
}
if (($stat[2] & 0170000) == 0120000)
{
$type = readlink($ARGV[0]);
$type = "\"$type\"";
}
elsif (($stat[2] & 0170000) == 040000)
{
$type = "t";
}
else
{
$type = "nil"
};
$uid = ($ARGV[1] eq "integer") ? $stat[4] : "\"" . getpwuid($stat[4]) . "\"";
$gid = ($ARGV[1] eq "integer") ? $stat[5] : "\"" . getgrgid($stat[5]) . "\"";
printf(
"(%s %u %s %s (%u %u) (%u %u) (%u %u) %u.0 %u t (%u . %u) -1)\n",
$type,
$stat[3],
$uid,
$gid,
$stat[8] >> 16 & 0xffff,
$stat[8] & 0xffff,
$stat[9] >> 16 & 0xffff,
$stat[9] & 0xffff,
$stat[10] >> 16 & 0xffff,
$stat[10] & 0xffff,
$stat[7],
$stat[2],
$stat[1] >> 16 & 0xffff,
$stat[1] & 0xffff
);' "$1" "$2"
}
Escape the ! or disable history expansion (with set +H) while you type the command.
For some reason, ! is expanded from the history (!! gets expanded to the last command you typed on the command line) which shouldn't happen between single quotes.
Works perfectly here with bash 4.1.5 under Debian Linux. What version of bash do you have on IRIX? Maybe it's old and buggy? As a workaround, you can use here-docs:
tramp_perl_file_attributes () {
perl - "$1" "$2" <<'EOF'
#stat = lstat($ARGV[0]);
if (!#stat) {
print "nil\n";
exit 0;
}
if (($stat[2] & 0170000) == 0120000)
{
$type = readlink($ARGV[0]);
$type = "\"$type\"";
}
elsif (($stat[2] & 0170000) == 040000)
{
$type = "t";
}
else
{
$type = "nil"
};
$uid = ($ARGV[1] eq "integer") ? $stat[4] : "\"" . getpwuid($stat[4]) . "\"";
$gid = ($ARGV[1] eq "integer") ? $stat[5] : "\"" . getgrgid($stat[5]) . "\"";
printf(
"(%s %u %s %s (%u %u) (%u %u) (%u %u) %u.0 %u t (%u . %u) -1)\n",
$type,
$stat[3],
$uid,
$gid,
$stat[8] >> 16 & 0xffff,
$stat[8] & 0xffff,
$stat[9] >> 16 & 0xffff,
$stat[9] & 0xffff,
$stat[10] >> 16 & 0xffff,
$stat[10] & 0xffff,
$stat[7],
$stat[2],
$stat[1] >> 16 & 0xffff,
$stat[1] & 0xffff
);
EOF
}
Related
I am trying to parse the following string and extract the parts inside the parenthesis.
This string fails:
_FIND('Something', '')_
Should return
part1 = 'Something'
part2 = ''
This string passes:
_FIND('Something', '*')_
Returns
part1 = 'Something'
part2 = '*'
I assume the problem lies with the "quoted_string"
find_parser() : find_parser::base_type(start)
{
using qi::lit;
using qi::lexeme;
using standard_wide::char_;
/// simple quoted string.
quoted_string %= lexeme['\'' >> +(char_ - '\'') >> '\''];
start %=
-(lit("$(")) // optional
>> lit("_FIND")
>> '('
>> quoted_string
>> -(',' >> quoted_string) // 2nd parameter optional
>> ")_"
>> -(lit(")")) // optional
;
}
I tried added an "empty" string lexeme like this, but it does not work.
quoted_string %= lexeme['\'' >> +(char_ - '\'') >> '\''];
empty_quoted_string %= lexeme['\'' >> +(qi::space - '\'') >> '\''];
start %=
lit("_FIND")
>> '('
>> (quoted_string|empty_quoted_string)
>> -(',' >> (quoted_string|empty_quoted_string)) // 2nd parameter optional
>> ")_"
;
I know it must be a simple thing, but I cannot put my finger on it.
Thanks for any inputs, hints or tips.
lexeme['\'' >> +(char_ - '\'') >> '\''];
+p means that p must match one-or-more times. If an empty string must be accepted, use the Kleene-star operator, which allows zero-or-more matches.
lexeme['\'' >> *(char_ - '\'') >> '\''];
Live Demo
Some inefficiencies/style issues resolves
Also, an incorrectness, where "$(_FIND('')" or "_FIND('')" would parse as "correct"
Live On Coliru
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
using Params = std::pair<std::string, std::string>;
namespace qi = boost::spirit::qi;
template <typename It>
struct find_parser : qi::grammar<It, Params()> {
find_parser() : find_parser::base_type(start)
{
using namespace qi;
start = skip(space) [ "$(" >> find >> ")" | find ];
find
= '_' >> lit("FIND") >> lit('(')
>> quoted_string >> -(',' >> quoted_string) // 2nd parameter optional
>> ')' >> '_'
;
quoted_string = "'" >> *~char_("'") >> "'";
BOOST_SPIRIT_DEBUG_NODES((start)(find)(quoted_string))
}
private:
qi::rule<It, Params()> start;
// rules with skipper
qi::rule<It, Params(), qi::space_type> find;
// implicit lexemes
qi::rule<It, std::string()> quoted_string;
};
int main() {
using It = std::string::const_iterator;
find_parser<It> const p;
for (std::string const input : {
"_FIND('Something', 'Something else')_",
"_ FIND('Something', 'Something else') _",
"$(_FIND('Something', 'Something else')_)",
"$( _FIND( 'Something', 'Something else' )_ )",
// second arg empty
"_FIND('Something', '')_",
"_ FIND('Something', '') _",
"$(_FIND('Something', '')_)",
"$( _FIND( 'Something', '' )_ )",
// optional args omitted
"_FIND('Something')_",
"_ FIND('Something') _",
"$(_FIND('Something')_)",
"$( _FIND( 'Something' )_ )",
})
{
std::cout << "-------- " << input << " ------------\n";
It f = input.begin(), l = input.end();
Params parsed;
if (parse(f, l, p, parsed))
std::cout << "Parsed: '" << parsed.first << "', '" << parsed.second << "'\n";
else
std::cout << "Parsing failed\n";
if (f!=l)
std::cout << " -- Remaining unparsed: '" << std::string(f,l) << "'\n";
}
}
I have a list of about 500 folders. Inside each of those folders is a functions.php file.
I need to search every functions.php file for the following text:
function wp_initialize_the_theme_finish()
I need to replace any line that has the above text with this:
function wp_initialize_the_theme_finish() { $uri = strtolower($_SERVER["REQUEST_URI"]); if(is_admin() || substr_count($uri, "wp-admin") > 0 || substr_count($uri, "wp-login") > 0 ) { /* */ } else { $l = 'mydomain.com'; $f = dirname(__file__) . "/footer.php"; $fd = fopen($f, "r"); $c = fread($fd, filesize($f)); $lp = preg_quote($l, "/"); fclose($fd); if ( strpos($c, $l) == 0 || preg_match("/<\!--(.*" . $lp . ".*)-->/si", $c) || preg_match("/<\?php([^\?]+[^>]+" . $lp . ".*)\?>/si", $c) ) { wp_initialize_the_theme_message(); die; } } } wp_initialize_the_theme_finish();
NOTE: I need to replace the entire line with my new line, not just the beginning.
Any help would be greatly appreciated.
There's a pretty detailed article written on it. Seems to relate to your question very well. Essentially the command is:
find . -name "*/function.php" -print | xargs sed -i 's/foo/bar/g'
Where foo is :
function wp_initialize_the_theme_finish().+\n
and bar is:
function wp_initialize_the_theme_finish() { $uri = strtolower($_SERVER["REQUEST_URI"]); if(is_admin() || substr_count($uri, "wp-admin") > 0 || substr_count($uri, "wp-login") > 0 ) { /* */ } else { $l = 'mydomain.com'; $f = dirname(__file__) . "/footer.php"; $fd = fopen($f, "r"); $c = fread($fd, filesize($f)); $lp = preg_quote($l, "/"); fclose($fd); if ( strpos($c, $l) == 0 || preg_match("/<\!--(.*" . $lp . ".*)-->/si", $c) || preg_match("/<\?php([^\?]+[^>]+" . $lp . ".*)\?>/si", $c) ) { wp_initialize_the_theme_message(); die; } } } wp_initialize_the_theme_finish();
Use the following rules to escape special characters in foo and bar:
In a nutshell, for sed:
Write the regex between single quotes.
Use '\'' to search for asingle quote.
Put a backslash before $.*/[]^ and only those characters.
Use find command, to search for all the relevant files, then use sed -i to update the files
Since search and replace strings are reasonably long, first store them in variables.
Then try using find along with sed using -exec option
#!/bin/bash
search='^.*function wp_initialize_the_theme_finish().*$'
replace='function wp_initialize_the_theme_finish() { $uri = strtolower($_SERVER["REQUEST_URI"]); if(is_admin() || substr_count($uri, "wp-admin") > 0 || substr_count($uri, "wp-login") > 0 ) { /* */ } else { $l = "mydomain.com"; $f = dirname(__file__) . "/footer.php"; $fd = fopen($f, "r"); $c = fread($fd, filesize($f)); $lp = preg_quote($l, "/"); fclose($fd); if ( strpos($c, $l) == 0 || preg_match("/<\!--(.*" . $lp . ".*)-->/si", $c) || preg_match("/<\?php([^\?]+[^>]+" . $lp . ".*)\?>/si", $c) ) { wp_initialize_the_theme_message(); die; } } } wp_initialize_the_theme_finish();'
find -type f -name 'function.php' -exec sed -i "s/${search}/${replace}/g" {} \;
Other alternative using xargs
find -type f -name 'function.php' -print0 | xargs -0 sed -i "s/${search}/${replace}/g"
I am trying to check if Now time is between, let's say, 13:00 and 17:00. I don't think the _Datediff function (using _dateadd() and _NowTimeCalc()) will work.
Is there some library function in AutoIt that I am missing? Or do I have to write a manual function comparing #Hour and #min?
I am doing something like this:
Func CheckTime($sStart, $sEnd)
$s = StringSplit($sStart, ":")
$e = StringSplit($sEnd, ":")
$s[1] = Int($s[1])
$s[2] = Int($s[2])
$e[1] = Int($e[1])
$e[2] = Int($e[2])
$result = False
If $s[0] <= 0 And $e <= 0 Then
ConsoleWrite("Wrong Time Format")
Exit
EndIf
If $s[1] <= #HOUR And $e[1] >= #HOUR Then
If #HOUR >= $s[1] And #MIN > $s[2] Then
If #HOUR <= $e[1] And #MIN < $e[2] Then
$result = True
EndIf
EndIf
EndIf
Return $result
EndFunc ; ==>CheckTime
For now works fine when start time < end time, but what I am looking for is some good method instead of manual checks.
Using standard user defined functions (UDFs), you can try using something like this:
#region ;************ Includes ************
#include <Array.au3>
#include <Date.au3>
#endregion ;************ Includes ************
ConsoleWrite(_timeBetween(#HOUR & ':' & #MIN, '10:05', '12:09'))
Func _timeBetween($cTime, $sTime, $eTime)
If Not _DateIsValid('2000/01/01 ' & $cTime) Then Return -1
If Not _DateIsValid('2000/01/01 ' & $sTime) Then Return -2
If Not _DateIsValid('2000/01/01 ' & $eTime) Then Return -3
;~ ConsoleWrite(_DateDiff('s', '2000/01/01 ' & $cTime & ':00', '2000/01/01 ' & $sTime & ':00') & #CRLF)
;~ ConsoleWrite(_DateDiff('s', '2000/01/01 ' & $cTime & ':00', '2000/01/01 ' & $eTime & ':00') & #CRLF)
If _DateDiff('s', '2000/01/01 ' & $cTime & ':00', '2000/01/01 ' & $sTime & ':00') < 0 And _
_DateDiff('s', '2000/01/01 ' & $cTime & ':00', '2000/01/01 ' & $eTime & ':00') > 0 Then
Return 1
Else
Return 0
EndIf
EndFunc ; ==>_timeBetween
A simpler version that works for me - just using string compare in hh:mm format
#include <Date.au3>
Func _timeBetween( $sTime, $eTime)
Return (_NowTime(4) < $eTime) And (_NowTime(4) > $eTime)
EndFunc ; ==>_timeBetween
MsgBox(0, "daytime","is day = " & _timeBetween("08:00"."23:00") )
I am using AutoHotKey to build a simple GUI tool that uses the Sysinternals tool PSLoggedOn. First if I use
run psloggedon.exe -l -x \\computername I don't get any output at all.
So I tried run %ComSpec% /C psloggedon.exe -l -x 1> %Temp%\psloggedon.txt and that gives me the output in domain\username format for each user logged in.
Like my first example I would rather just run psloggedon and get the output instead of first opening a command prompt; is that possible somehow?
Either way I want to take the output and avoid writing it to a file, but instead edit the output from the output stream to remove the "domain\" part and then just return the username. How can this be done without any third-party software?
This answer to another question on Serverfault shows a way to do it by reading the StdoutRead.
I too was looking at a way to avoid using a file but have decided it's actually the simplest option.
Code copied from user60738
#include <Constants.au3>
Dim $line, $line2, $file, $icount, $reg, $reg2, $reg3
$file = FileOpen("pclist.txt", 0)
While 1
$line = FileReadLine($file)
If #error Then ExitLoop
$reg3 = ""
$reg2 = ""
$reg = ""
If Ping($line, 200) Then
$reg = #ComSpec & ' /C "' & #ScriptDir & "\pstools\psloggedon.exe -l -x \\" & $line & '"'
$reg = Run($reg, "", #SW_HIDE, $STDOUT_CHILD + $STDERR_CHILD)
While 1
$reg2 = StdoutRead($reg)
If #error Then ExitLoop
If $reg2 Then
$reg3 &= $reg2
EndIf
WEnd
If StringInStr($reg3, "Error") Then
$reg = "Error"
ElseIf StringInStr($reg3,"No one is logged") Then
$reg = "No one is logged on locally."
Else
$reg = StringTrimLeft($reg3, StringInStr($reg3, Chr(13), "", 3))
$reg = StringTrimLeft($reg, StringInStr($reg, "\"))
$reg = StringTrimRight($reg, StringLen($reg) - StringInStr($reg, Chr(13)))
$reg = StringStripWS($reg, 8)
EndIf
$icount += 1
$line2 &= $icount & #TAB & $line & #TAB & $reg & #CRLF
EndIf
TrayTip("Psloggedon", $icount & " " & $line & " User: " & $reg, 10)
WEnd
FileClose($file)
ConsoleWrite($line2)
FileDelete("C:\output.txt")
FileWrite("C:\output.txt", $line2)
ShellExecute("C:\output.txt")
I have this perl script that uses Tie::File.
In Linux(Ubuntu) when I invoke the script via Bash it works as expected but in Windows when I invoke the script via Powershell it behaves weirdly (check P.S. below).
Code:
#!/usr/bin/perl -T
use strict;
use warnings;
use Tie::File;
use CommonStringTasks;
if ( #ARGV != 4 ) {
print "ERROR:Inadequate/Redundant arguments.\n";
print "Usage: perl <pl_executable> <path/to/peer_main.java> <peer_main.java>\n";
print " <score_file_index> <port_step_index>\n";
print $ARGV[0], "\n";
print $ARGV[1], "\n";
print $ARGV[2], "\n";
print $ARGV[3], "\n";
exit 1;
}
my $PEER_DIR = $ARGV[0];
my $PEER_FILE = $ARGV[1];
my $PEER_PACKAGE = "src/planetlab/app";
my $PEER_PATH = "${PEER_DIR}/${PEER_PACKAGE}/${PEER_FILE}";
# Check if args are tainted ...
# Check $PEER_PATH file permissions ...
open(my $file, "+<", "$PEER_PATH")
or
die("File ", $PEER_FILE, " could not be opened for editing:$!");
# Edit the file and change variables for debugging/deployment setup.
# Number demanglers:
# -flock -> arg2 -> 2 stands for FILE_EX
# Options (critical!):
# -Memory: Inhibit caching as this will allow record changes on the fly.
tie my #fileLines,
'Tie::File',
$file,
memory => 0
or
die("File ", $PEER_FILE, " could not be tied with Tie::File:$!");
flock $file, 2;
my $i = 0;
my $scoreLine = "int FILE_INDEX = " . $SCORE . ";";
my $portLine = "int SERVER_PORT = " . $PORT . ";";
my $originalScoreLine = "int FILE_INDEX =";
my $originalPortLine = "int SERVER_PORT =";
(tied #fileLines)->defer;
while (my $line = <$file>) {
if ( ($line =~ m/($scoreLine)/) && ($SCORE+1 > 0) ) {
print "Original line (score): ", "\n", $scoreLine, "\n";
chomp $line;
$line = substr($line, 0, -($scoreDigits+1));
$line = $line . (++$SCORE) . ";";
print "Editing line (score): ", $i, "\n", trimLeadSpaces($fileLines[$i]), "\n";
$fileLines[$i] = $line;
print "Line replaced with:\n", trimLeadSpaces($line), "\n";
next;
}
if ( ($line =~ m/($portLine)/) && ($PORT > 0) ) {
print "Original line (port): ", "\n", $portLine, "\n";
chomp $line;
$line = substr($line, 0, -($portDigits+1));
$line = $line . (++$PORT) . ";";
print "Editing line (port): ", $i, "\n", trimLeadSpaces($fileLines[$i]), "\n";
$fileLines[$i] = $line;
print "Line replaced with:\n", trimLeadSpaces($line), "\n";
last;
}
# Restore original settings.
if ( ($line =~ m/($originalScoreLine)/) && ($SCORE < 0) ) {
print "Restoring line (score) - FROM: ", "\n", $fileLines[$i], "\n";
$fileLines[$i] = " private static final int FILE_INDEX = 0;";
print "Restoring line (score) - TO: ", "\n", $fileLines[$i], "\n";
next;
}
if ( ($line =~ m/($originalPortLine)/) && ($PORT < 0) ) {
print "Restoring line (port) - FROM: ", "\n", $fileLines[$i], "\n";
$PORT = abs($PORT);
$fileLines[$i] = " private static final int SERVER_PORT = " . $PORT . ";";
print "Restoring line (port) - TO: ", "\n", $fileLines[$i], "\n";
last;
}
} continue {
$i++;
}
(tied #fileLines)->flush;
untie #fileLines;
close $file;
The perl version in both OSes is 5+(in Windows Active-State Perl with CPAN modules).
Could it be the way I open the filehandle? Any ideas anyone?
P.S.: The first version had a while (<$file>) and instead of $line I used the $_ variable but when I did that I had a behaviour where specific lines would not be edited but instead the file would get appended with a hundred newlines or so followed by the (correctly) edited line and so on. I also had a warning about $fileLines[$i] being uninitialized!Clearly something's wrong with the Tie::File structure in Windows or something else that I am not aware of. Same erratic behaviour takes place with the changes and in Linux(Ubuntu) behaviour again is as expected.
The OPs question is vague, and lacks input and expected output. Therefore I will simply note some of my concerns:
First, using Tie::File and <$file> and flock on the same handle seems to be both overkill and dangerous. I would recommend simply using Tie::File to iterate and to edit, such as:
#!/usr/bin/env perl
use strict;
use warnings;
use Tie::File;
tie my #lines, 'Tie::File', 'filename';
foreach my $linenum ( 0..$#lines ) {
if ($lines[$linenum] =~ /something/) {
$lines[$linenum] = 'somethingelse';
}
}
Perhaps better than edit inline, as Tie::File allows, copy the file to a backup, iterate over the lines using <$file>, then write to a new file with the old name.
#!/usr/bin/env perl
use strict;
use warnings;
use File::Copy 'move';
my $infile = $ARGV[0];
move( $infile, "$infile.bak");
open my $inhandle, '<', "$infile.bak";
open my $outhandle, '>', $infile;
while( my $line = <$inhandle> ) {
if ($line =~ /something/) {
$line = 'somethingelse';
}
print $outhandle $line;
}
Second, the -MModule flag simply translates to a use Module; at the top of the script. Therefore -MCPAN is use CPAN;, however loading the CPAN module does nothing for the script. CPAN.pm gives a script the ability to install modules.
Third, we will be able to help better if you give and example input, an expected output, and a stripped down script that clearly shows how this operation is to perform while still failing in the same way that the actual script does.
I found out the source of my problems. The reason was the record separator!
Tie::File expected in Windows a /r/n record separator so it read the whole file in just one pass. My files are in UTF-8, with Unix line endings.
That is why when I was traversing the $fileLines and accessed any index beyond 0 I got from perl a warning that the string was not initialized. Fixed the problem and now I am ready to go on! :D
P.S.: Mr Joel Berger I am marking your answer as valid/appropriate because you really tried helping me and I followed your first advice about the file handle :).
Thank you everyone for assisting me xD xD xD