I have the following command which displays to me my current IP address:
ifconfig -a | awk 'BEGIN { count=0; } { if ( $1 ~ /inet/ ) { count++; if( count==2 ) { print $2; } } }'
I'd like to be able to wrap this command into an alias such as:
alias myip="ifconfig -a | awk 'BEGIN { count=0; } { if ( $1 ~ /inet/ ) { count++; if( count==2 ) { print $2; } } }'"
or even a function like so:
function myip() { ifconfig -a | awk 'BEGIN { count=0; } { if ( $1 ~ /inet/ ) { count++; if( count==2 ) { print $2; } } }' }
However, none of these solutions work and I get this error:
syntax error near unexpected token ``{ifconfig'
I've tried this:
alias myip='ifconfig -a | awk '\''BEGIN{ count=0; } { if ( $1 ~ /inet/ ) { count++; if( count==2 ) { print $2; } } }'\'''
but no luck.
How would I be able to accomplish this task?
1) Your function needs a ; before the closing }
function myip() { ifconfig -a | awk 'BEGIN { count=0; } { if ( $1 ~ /inet/ ) { count++; if( count==2 ) { print $2; } } }'; }
HERE --^
2) You only need either function or (), but not both. (Although this depends on your shell.)
function myip { ifconfig -a | awk 'BEGIN { count=0; } { if ( $1 ~ /inet/ ) { count++; if( count==2 ) { print $2; } } }'; }
3) You probably didn't unalias your previous attempt before you did your function attempt
unalias myip
After making those changes, the function should work without a syntax error.
Related
Here's my PS1 variable:
PS1='\u:\W$(__git_ps1 "\e[32m\][%s]\e[0m\]")$ '
Works great for picking up my Git branch, but it has the unfortunate side-effect of wrapping the lines when the colours are active, so that they overlap when you use long commands.
Can anyone with magic PS1 skills help me out to fix this?
Got it, needed to escape the colours properly.
Fix:
PS1='\u:\W$(__git_ps1 "\[\e[32m\][%s]\[\e[0m\]")$ '
May I suggest the following method for colors in Bash, it makes the code much more readable and alot harder for you to miss an escape or two.
Put the following in your ~/.bashrc
BLACK=$(tput setaf 0)
RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
LIME_YELLOW=$(tput setaf 190)
YELLOW=$(tput setaf 3)
POWDER_BLUE=$(tput setaf 153)
BLUE=$(tput setaf 4)
MAGENTA=$(tput setaf 5)
CYAN=$(tput setaf 6)
WHITE=$(tput setaf 7)
BRIGHT=$(tput bold)
NORMAL=$(tput sgr0)
BLINK=$(tput blink)
REVERSE=$(tput smso)
UNDERLINE=$(tput smul)
A sample PS1 (or really anything that prints to the screen) would be:
PS1="\[${WHITE}\](\[${YELLOW}\]\u#\h\[${WHITE}\])\[${NORMAL}\]$ "
You need only put \[ \] around the color words.
If you have a 256-color terminal, you can experiment with other numerical values to 'tput setaf' all the way up to 255.
These are the color functions I use regularly... wrote them years ago and have gotten so used to them that they're a regular part of my scripting. Just stick this code block into your .bashrc file, start a new session, and you're set!
I use these as colorful/stylish printf replacements:
## ∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞ ##
## ∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞ [ Aesthir's Color Functions ] ∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞ ##
## ∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞ ##
Normal () { printf '\e[m'"$*"; } ; Tblack () { printf '\e[0;30m'"$*"'\e[m'; }
TNormal () { printf '\e[m'"$*"; } ; Tred () { printf '\e[0;31m'"$*"'\e[m'; }
Bold () { printf '\e[1m'"$*"'\e[m'; } ; Tgreen () { printf '\e[0;32m'"$*"'\e[m'; }
TBold () { printf '\e[1m'"$*"'\e[m'; } ; Tbrown () { printf '\e[0;33m'"$*"'\e[m'; }
Underline () { printf '\e[4m'"$*"'\e[m'; } ; Tyellow () { printf '\e[0;33m'"$*"'\e[m'; }
TUnderline () { printf '\e[4m'"$*"'\e[m'; } ; Tblue () { printf '\e[0;34m'"$*"'\e[m'; }
Flash () { printf '\e[5m'"$*"'\e[m'; } ; Tmagenta () { printf '\e[0;35m'"$*"'\e[m'; }
TFlash () { printf '\e[5m'"$*"'\e[m'; } ; Tpurple () { printf '\e[0;35m'"$*"'\e[m'; }
Invert () { printf '\e[7m'"$*"'\e[m'; } ; Taqua () { printf '\e[0;36m'"$*"'\e[m'; }
TInvert () { printf '\e[7m'"$*"'\e[m'; } ; Tcyan () { printf '\e[0;36m'"$*"'\e[m'; }
Invisible () { printf '\e[8m'"$*"'\e[m'; } ; Tgrey () { printf '\e[0;37m'"$*"'\e[m'; }
TInvisible () { printf '\e[8m'"$*"'\e[m'; } ; Twhite () { printf '\e[0;37m'"$*"'\e[m'; }
## ∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞ Bold Color Text ∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞ ## ∞∞∞∞∞∞∞∞∞∞∞∞ Underlined Color Text ∞∞∞∞∞∞∞∞∞∞∞∞∞ ##
TblackB () { printf '\e[1;30m'"$*"'\e[m'; } ; TblackU () { printf '\e[4;30m'"$*"'\e[m'; }
TgreyB () { printf '\e[1;30m'"$*"'\e[m'; } ; TredU () { printf '\e[4;31m'"$*"'\e[m'; }
TredB () { printf '\e[1;31m'"$*"'\e[m'; } ; TgreenU () { printf '\e[4;32m'"$*"'\e[m'; }
TgreenB () { printf '\e[1;32m'"$*"'\e[m'; } ; TbrownU () { printf '\e[4;33m'"$*"'\e[m'; }
TbrownB () { printf '\e[1;33m'"$*"'\e[m'; } ; TyellowU () { printf '\e[4;33m'"$*"'\e[m'; }
TyellowB () { printf '\e[1;33m'"$*"'\e[m'; } ; TblueU () { printf '\e[4;34m'"$*"'\e[m'; }
TblueB () { printf '\e[1;34m'"$*"'\e[m'; } ; TmagentaU () { printf '\e[4;35m'"$*"'\e[m'; }
TmagentaB () { printf '\e[1;35m'"$*"'\e[m'; } ; TpurpleU () { printf '\e[4;35m'"$*"'\e[m'; }
TpurpleB () { printf '\e[1;35m'"$*"'\e[m'; } ; TaquaU () { printf '\e[4;36m'"$*"'\e[m'; }
TaquaB () { printf '\e[1;36m'"$*"'\e[m'; } ; TcyanU () { printf '\e[4;36m'"$*"'\e[m'; }
TcyanB () { printf '\e[1;36m'"$*"'\e[m'; } ; TgreyU () { printf '\e[4;37m'"$*"'\e[m'; }
TwhiteB () { printf '\e[1;37m'"$*"'\e[m'; } ; TwhiteU () { printf '\e[4;37m'"$*"'\e[m'; }
## ∞∞∞∞∞∞∞∞∞∞∞∞∞ Flashing Color Text ∞∞∞∞∞∞∞∞∞∞∞∞∞∞ ## ∞∞∞∞∞∞∞∞∞∞∞∞∞ Inverted Color Text ∞∞∞∞∞∞∞∞∞∞∞∞∞∞ ##
TblackF () { printf '\e[5;30m'"$*"'\e[m'; } ; TblackI () { printf '\e[7;40m'"$*"'\e[m'; }
TredF () { printf '\e[5;31m'"$*"'\e[m'; } ; TredI () { printf '\e[7;41m'"$*"'\e[m'; }
TgreenF () { printf '\e[5;32m'"$*"'\e[m'; } ; TgreenI () { printf '\e[7;42m'"$*"'\e[m'; }
TbrownF () { printf '\e[5;33m'"$*"'\e[m'; } ; TbrownI () { printf '\e[7;43m'"$*"'\e[m'; }
TyellowF () { printf '\e[5;33m'"$*"'\e[m'; } ; TyellowI () { printf '\e[7;43m'"$*"'\e[m'; }
TblueF () { printf '\e[5;34m'"$*"'\e[m'; } ; TblueI () { printf '\e[7;44m'"$*"'\e[m'; }
TmagentaF () { printf '\e[5;35m'"$*"'\e[m'; } ; TmagentaI () { printf '\e[7;45m'"$*"'\e[m'; }
TpurpleF () { printf '\e[5;35m'"$*"'\e[m'; } ; TpurpleI () { printf '\e[7;45m'"$*"'\e[m'; }
TaquaF () { printf '\e[5;36m'"$*"'\e[m'; } ; TaquaI () { printf '\e[7;46m'"$*"'\e[m'; }
TcyanF () { printf '\e[5;36m'"$*"'\e[m'; } ; TcyanI () { printf '\e[7;46m'"$*"'\e[m'; }
TgreyF () { printf '\e[5;37m'"$*"'\e[m'; } ; TgreyI () { printf '\e[7;47m'"$*"'\e[m'; }
TwhiteF () { printf '\e[5;37m'"$*"'\e[m'; } ; TwhiteI () { printf '\e[7;47m'"$*"'\e[m'; }
## ∞∞∞∞∞∞∞∞∞∞∞∞∞ Invisible Color Text ∞∞∞∞∞∞∞∞∞∞∞∞∞ ## ∞∞∞∞∞∞∞∞ Plain Text on Color Background ∞∞∞∞∞∞∞∞ ##
TblackV () { printf '\e[8;30m'"$*"'\e[m'; } ; Bblack () { printf '\e[m'"$*"'\e[m'; }
TredV () { printf '\e[8;31m'"$*"'\e[m'; } ; Bred () { printf '\e[0;41m'"$*"'\e[m'; }
TgreenV () { printf '\e[8;32m'"$*"'\e[m'; } ; Bgreen () { printf '\e[0;42m'"$*"'\e[m'; }
TbrownV () { printf '\e[8;33m'"$*"'\e[m'; } ; Bbrown () { printf '\e[0;43m'"$*"'\e[m'; }
TyellowV () { printf '\e[8;33m'"$*"'\e[m'; } ; Byellow () { printf '\e[0;43m'"$*"'\e[m'; }
TblueV () { printf '\e[8;34m'"$*"'\e[m'; } ; Bblue () { printf '\e[0;44m'"$*"'\e[m'; }
TmagentaV () { printf '\e[8;35m'"$*"'\e[m'; } ; Bmagenta () { printf '\e[0;45m'"$*"'\e[m'; }
TpurpleV () { printf '\e[8;35m'"$*"'\e[m'; } ; Bpurple () { printf '\e[0;45m'"$*"'\e[m'; }
TaquaV () { printf '\e[8;36m'"$*"'\e[m'; } ; Baqua () { printf '\e[0;46m'"$*"'\e[m'; }
TcyanV () { printf '\e[8;36m'"$*"'\e[m'; } ; Bcyan () { printf '\e[0;46m'"$*"'\e[m'; }
TgreyV () { printf '\e[8;37m'"$*"'\e[m'; } ; Bgrey () { printf '\e[0;47m'"$*"'\e[m'; }
TwhiteV () { printf '\e[8;37m'"$*"'\e[m'; } ; Bwhite () { printf '\e[0;47m'"$*"'\e[m'; }
## ∞∞∞∞∞∞∞∞∞ Bold Text on Color Background ∞∞∞∞∞∞∞∞ ## ∞∞∞∞∞∞ Underlined Text on Color Background ∞∞∞∞∞ ##
BblackB () { printf '\e[1;40m'"$*"'\e[m'; } ; BblackU () { printf '\e[4;40m'"$*"'\e[m'; }
BredB () { printf '\e[1;41m'"$*"'\e[m'; } ; BredU () { printf '\e[4;41m'"$*"'\e[m'; }
BgreenB () { printf '\e[1;42m'"$*"'\e[m'; } ; BgreenU () { printf '\e[4;42m'"$*"'\e[m'; }
BbrownB () { printf '\e[1;43m'"$*"'\e[m'; } ; BbrownU () { printf '\e[4;43m'"$*"'\e[m'; }
ByellowB () { printf '\e[1;43m'"$*"'\e[m'; } ; ByellowU () { printf '\e[4;43m'"$*"'\e[m'; }
BblueB () { printf '\e[1;44m'"$*"'\e[m'; } ; BblueU () { printf '\e[4;44m'"$*"'\e[m'; }
BmagentaB () { printf '\e[1;45m'"$*"'\e[m'; } ; BmagentaU () { printf '\e[4;45m'"$*"'\e[m'; }
BpurpleB () { printf '\e[1;45m'"$*"'\e[m'; } ; BpurpleU () { printf '\e[4;45m'"$*"'\e[m'; }
BaquaB () { printf '\e[1;46m'"$*"'\e[m'; } ; BaquaU () { printf '\e[4;46m'"$*"'\e[m'; }
BcyanB () { printf '\e[1;46m'"$*"'\e[m'; } ; BcyanU () { printf '\e[4;46m'"$*"'\e[m'; }
BgreyB () { printf '\e[1;47m'"$*"'\e[m'; } ; BgreyU () { printf '\e[4;47m'"$*"'\e[m'; }
BwhiteB () { printf '\e[1;47m'"$*"'\e[m'; } ; BwhiteU () { printf '\e[4;47m'"$*"'\e[m'; }
## ∞∞∞∞∞∞∞ Flashing Text on Color Background ∞∞∞∞∞∞ ## ∞∞∞∞∞∞∞ Inverted Text on Color Background ∞∞∞∞∞∞ ##
BblackF () { printf '\e[5;40m'"$*"'\e[m'; } ; BblackI () { printf '\e[7;30m'"$*"'\e[m'; }
BredF () { printf '\e[5;41m'"$*"'\e[m'; } ; BredI () { printf '\e[7;31m'"$*"'\e[m'; }
BgreenF () { printf '\e[5;42m'"$*"'\e[m'; } ; BgreenI () { printf '\e[7;32m'"$*"'\e[m'; }
BbrownF () { printf '\e[5;43m'"$*"'\e[m'; } ; BbrownI () { printf '\e[7;33m'"$*"'\e[m'; }
ByellowF () { printf '\e[5;43m'"$*"'\e[m'; } ; ByellowI () { printf '\e[7;33m'"$*"'\e[m'; }
BblueF () { printf '\e[5;44m'"$*"'\e[m'; } ; BblueI () { printf '\e[7;34m'"$*"'\e[m'; }
BmagentaF () { printf '\e[5;45m'"$*"'\e[m'; } ; BmagentaI () { printf '\e[7;35m'"$*"'\e[m'; }
BpurpleF () { printf '\e[5;45m'"$*"'\e[m'; } ; BpurpleI () { printf '\e[7;35m'"$*"'\e[m'; }
BaquaF () { printf '\e[5;46m'"$*"'\e[m'; } ; BaquaI () { printf '\e[7;36m'"$*"'\e[m'; }
BcyanF () { printf '\e[5;46m'"$*"'\e[m'; } ; BcyanI () { printf '\e[7;36m'"$*"'\e[m'; }
BgreyF () { printf '\e[5;47m'"$*"'\e[m'; } ; BgreyI () { printf '\e[7;37m'"$*"'\e[m'; }
BwhiteF () { printf '\e[5;47m'"$*"'\e[m'; } ; BwhiteI () { printf '\e[7;37m'"$*"'\e[m'; }
## ∞∞∞∞∞∞ Invisible Text on Color Background ∞∞∞∞∞∞ ## ∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞ Color Code Notes ∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞ ##
BblackV () { printf '\e[8;40m'"$*"'\e[m'; } ## Unless I missed something or made a mistake, I ##
BredV () { printf '\e[8;41m'"$*"'\e[m'; } ## calculate a total of 7681 different color codes, ##
BgreenV () { printf '\e[8;42m'"$*"'\e[m'; } ## none of which produce a duplicate result. ##
BbrownV () { printf '\e[8;43m'"$*"'\e[m'; } ## These will be fine for now. ##
ByellowV () { printf '\e[8;43m'"$*"'\e[m'; }
BblueV () { printf '\e[8;44m'"$*"'\e[m'; }
BmagentaV () { printf '\e[8;45m'"$*"'\e[m'; }
BpurpleV () { printf '\e[8;45m'"$*"'\e[m'; }
BaquaV () { printf '\e[8;46m'"$*"'\e[m'; }
BcyanV () { printf '\e[8;46m'"$*"'\e[m'; }
BgreyV () { printf '\e[8;47m'"$*"'\e[m'; }
BwhiteV () { printf '\e[8;47m'"$*"'\e[m'; }
## ∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞ ##
``
The only thing to keep in mind is when wanting a % percent sign or a \ backslash, you need to double them up inside:
like: printf "$(Tblue "%%s")\n" 'hi'
but not for Tblue "%s\n" 'hi'
or printf "$(Tblue "%s" 'hi')\n"
Since these use printf, you can do stuff like:
printf "hi $(Tred there) man $(BaquaI "%c" '!') $(Bold 'This \\t is %%s') %s\n" "$(BgreenB 'super')" "$(Bblue mega Colorful)"
or in an echo:
echo "hi $(Tred there) man $(BaquaI "%c" '!') $(Bold 'This \\t is %s' "$(BblackB 'super')") $(Bblue mega Colorful)"
A more useful example:
printf "\t%s Volume \"%s\" is not connected.\n" "$(TwhiteB [)$(TredB Error)$(TwhiteB \]:)" "$(Tbrown $Volume)"
Or with other commands:
eval "echo 'This is OSX' | sed 's:OSX:$(Invert [)$(TaquaF OSX)$(Invert ]):'"
Or something with a bit more swank:
find . -exec stat -f "Name: $(Tbrown %%N)%t%t$(Tpurple "->")%tPermissions: $(Tgreen %%Sp)" {} \;
Use your imagination! Feel free all to use these... the only thing I ask is if someone out there types up more of them, mix/matching them, like TcyanBgreenUI, or make up your own names... can you please post them for me and let me know about the post? or email them to me at aesth1r#me.com. I'm too lazy to type up all possibilities.
Enjoy!
-- Aesthir
I have a short script to search devices in a text file
Example db (inv.txt):
Rack: RG01
Rack_units: U11-U12
Serial: 10101NH
Name: Test01
Firmware: v1.01
Rack: RG05
Rack_units: U12-U13
Serial: 10893NE
Name: Test02
Firmware: v1.02
Rack: RK11
Rack_units: U14-U15
Serial: 10234JH
Name: Test03
Firmware: v1.01
[...]
This is my code:
#!/usr/bin/awk -f
/^Rack:/ {
inStanza = 1;
delete keep
idx = 0
}
inStanza {
keep[++idx] = $0
}
/^Serial:/ { if ($0 ~ find) { matched = 1; } else { matched = 0; } }
/^Firmware:/ && matched {
for(i=1;i<=idx;i++) print keep[i]
matched = 0;
inStanza = 0
}
I'd like to search by Serial: and Rack:, for example:
➜ ./search.awk -v find=RG01 inv.txt
Rack: RG01
Rack_units: U11-U12
Serial: 10101NH
Name: Test01
Firmware: v1.01
But right now it's working only for Serial:. I don't have any ideas how to do that. I tried to use OR, but it doesn't work for me
1. $1~/^(Serial:|Rack:)/ { if ($0 ~ find) { matched = 1; } else { matched = 0; } }
2. ($1 ~ /^Serial:/ || $1 ~ /^Rack:/) { if ($0 ~ find) { matched = 1; } else { matched = 0; } }
3. (/^Serial:/ || /^Rack:/) { if ($0 ~ find) { matched = 1; } else { matched = 0; } }
Any ideas?
The problem with your attempt is that it would zap the matched value if Serial: didn't match. So you want to refactor to only change matched if it wasn't already set for this record.
awk -v find="RG01" '
/^Rack:/ {
inStanza = 1;
delete keep
idx = 0
}
inStanza {
keep[++idx] = $0
}
/^(Rack|Serial):/ && !matched { matched = ($0 ~ find) }
/^Firmware:/ && matched {
for(i=1;i<=idx;i++) print keep[i]
matched = 0;
inStanza = 0
}' inv.txt
Demo: https://ideone.com/RL9S7L
Your fileformat is perfectly designed for an easy awk manipulation. By defining the record separator RS="", a single record is not the default line, but the entire block which you are interested in (empty lines separate the record separator). By defining the field separator to be a newline, we define the fields to be a single line in the record.
So the record $0 would be:
Rack: RG01
Rack_units: U11-U12
Serial: 10101NH
Name: Test01
Firmware: v1.01
and field $2 would equal Rack_units: U11-U12. Using split you can now split that in key-value pairs which makes it very practical to your problem:
awk -v find="STRING" '
BEGIN{RS=""; FS=OFS="\n"; ORS="\n\n"}
{for(i=1;i<=NF;++i) { split($i,a,":[ \t]*"); map[a[1]] = a[2] } }
(map["Rack"] == find || map("Serial") == find)
' file
I wrote a simple webserver which should continuously handle simultaneous requests. But, even after detaching the threads it doesn't handle simultaneous requests. Can someone help?
Webserver.pl
use HTTP::Daemon;
use threads;
my $webServer;
my $package_map = {"test" => "test"};
my $d = HTTP::Daemon->new(LocalAddr => $ARGV[0],
LocalPort => 80,
Listen => 20) || die;
print "Web Server started!\n";
print "Server Address: ", $d->sockhost(), "\n";
print "Server Port: ", $d->sockport(), "\n";
while (my $c = $d->accept) {
threads->create(\&process_req, $c)->detach();
}
sub process_req {
my $c = shift;
my $r = $c->get_request;
if ($r) {
if ($r->method eq "GET") {
my $path = $r->url->path();
my $service = $package_map->{$path};
if ($service) {
$response = $service->process_request($request);
}
}
}
$c->close;
undef($c);
}
test.pm
sub process_request
{
threads->create(\&testing)->detach();
my $response = HTTP::Response -> new (200);
$response -> header('Access-Control-Allow-Origin', '*');
$response -> content("Success");
return $response;
}
sub testing
{
my $command = 'echo "sleep 100" | ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 <dev_box>';
if (system($command) != 0) {
print "FAILED\n";
}
}
Here is code based on your example that works for me on Windows. Maybe you can show us how/where it fails for you:
#!perl
use strict;
use warnings;
use HTTP::Daemon;
use threads;
my $webServer;
#my $package_map = {"test" => "test"};
my $d = HTTP::Daemon->new(LocalAddr => $ARGV[0],
LocalPort => $ARGV[1] // 80,
Listen => 20) || die;
print "Web Server started!\n";
print "Server Address: ", $d->sockhost(), "\n";
print "Server Port: ", $d->sockport(), "\n";
while (my $c = $d->accept) {
warn "New connection";
threads->create(\&process_req, $c)->detach();
}
sub process_req {
my $c = shift;
while( my $r = $c->get_request ) {
if ($r) {
if ($r->method eq "GET") {
my $path = $r->url->path();
if (1) {
sleep 100;
$c->send_response( HTTP::Response->new(200, "OK", undef, "done\n") );
}
}
}
};
$c->close;
}
I had some working code that I've tried to multithread using the tutorial on dreamincode: http://www.dreamincode.net/forums/topic/255487-multithreading-in-perl/
The example code there seems to work fine, but I can't for the life of me work out why mine isn't. From putting in debug messages it seems to get all the way to the end of the subroutine with all of the threads, and then sit there for a while before hitting a segmentation fault and dumping the core. That being said I've also not managed to find the core dump files anywhere (Ubuntu 13.10).
If anyone has any suggested reading, or can see the error in the rather messy code below I'd be eternally grateful.
#!/usr/bin/env perl
use Email::Valid;
use LWP::Simple;
use XML::LibXML;
use Text::Trim;
use threads;
use DB_File;
use Getopt::Long;
my $sourcefile = "thislevel.csv";
my $startOffset = 0;
my $chunk = 10000;
my $num_threads = 8;
$result = GetOptions ("start=i" => \$startOffset, # numeric
"chunk=i" => \$chunk, # numeric
"file=s" => \$sourcefile, # string
"threads=i" => \$num_threads, #numeric
"verbose" => \$verbose); # flag
$tie = tie(#filedata, "DB_File", $sourcefile, O_RDWR, 0666, $DB_RECNO)
or die "Cannot open file $sourcefile: $!\n";
my $filenumlines = $tie->length;
if ($filenumlines>$startOffset + $chunk){
$numlines = $startOffset + $chunk;
} else {
$numlines = $filenumlines;
}
open (emails, '>>emails.csv');
open (errorfile, '>>errors.csv');
open (nxtlvl, '>>nextlevel.csv');
open (donefile, '>>donelines.csv');
my $line = '';
my $found = false;
my $linenum=0;
my #threads = initThreads();
foreach(#threads){
$_ = threads->create(\&do_search);
}
foreach(#threads){
$_->join();
}
close nxtlvl;
close emails;
close errorfile;
close donefile;
sub initThreads{
# An array to place our threads in
my #initThreads;
for(my $i = 1;$i<=$num_threads;$i++){
push(#initThreads,$i);
}
return #initThreads;
}
sub do_search{
my $id = threads->tid();
my $linenum=$startOffset-1+$id;
my $parser = XML::LibXML->new();
$parser->set_options({ recover => 2,
validation => 0,
suppress_errors => 1,
suppress_warnings => 1,
pedantic_parser => 0,
load_ext_dtd => 0, });
while ($linenum < $numlines) {
$found = false;
#full_line = split ',', $filedata[$linenum-1];
$line = trim(#full_line[1]);
$this_url = trim(#full_line[2]);
print "Thread $id Scanning $linenum of $filenumlines\: ";
printf "%.3f\%\n", 100 * $linenum / $filenumlines;
my $content = get trim($this_url);
if (!defined($content)) {
print errorfile "$this_url, no content\n";
}elsif (length($content)<100) {
print errorfile "$this_url, short\n";
}else {
my $doc = $parser->load_html(string => $content);
if(defined($doc)){
for my $anchor ( $doc->findnodes("//a[\#href]") )
{
$is_email = substr $anchor->getAttribute("href") ,7;
if(Email::Valid->address($is_email)) {
printf emails "%s, %s\n", $line, $is_email;
$found = true;
} else{
$link = $anchor->getAttribute("href");
if (substr lc(trim($link)),0,4 eq "http"){
printf nxtlvl "%s, %s\n", $line, $link;
} else {
printf nxtlvl "%s, %s/%s\n", $line, $line, $link;
}
}
}
}
if ($found=false){
my #lines = split '\n',$content;
foreach my $cline (#lines){
my #words = split ' ',$cline;
foreach my $word (#words) {
my #subwords = split '"',$word ;
foreach my $subword (#subwords) {
if(Email::Valid->address($subword)) {
printf emails "%s, %s\n", $line, $subword;
}
}
}
}
}
}
printf donefile "%s\n",$linenum;
$linenum = $linenum + $num_threads;
}
threads->exit();
}
In addition to sundry coding errors that mean my code should never ever be used as an example for other visitors, DB_File is not a thread-safe module.
Annoyingly, and perhaps misleadingly, it works absolutely as it should do right up until you close the threads that have been successfully accessing the file throughout your code.
There is forks::shared that should be drop in replacement for threads::shared, but how should I replace Thread::Queue?
I would like to convert following code to forks, if it is possible?
sub Qfac {
use threads;
use threads::shared;
use Thread::Queue;
my ($worker, $arrid, $arg) = #_;
$arrid ||= [];
$arg ||= {};
my %tr;
my %h :shared;
my %qe = map { $_ => Thread::Queue->new() } #$arrid;
for my $id (#$arrid) {
my $q = $qe{$id};
$tr{$id} = threads->create($arg, sub{
my $me = { id => $id };
while (my $item = $q->dequeue()) {
$me->{item} = $item;
eval { $worker->($me, \%h) };
$me->{err} = $# if $#;
my $temp = threads::shared::shared_clone($me);
{
lock (%h);
$h{$id} = $temp;
}
}
});
$tr{$id}->detach();
}
##
return sub {
my $act = shift;
if ($act eq "getshared") { return #_ ? #h{#_} : \%h }
elsif ($act eq "enqueue") { $_->enqueue(#_) for values %qe }
elsif ($act eq "getqe") { return \%qe }
elsif ($act eq "gettr") { return \%tr }
elsif ($act eq "getssize") { return threads->get_stack_size() }
elsif ($act eq "setssize") { return threads->set_stack_size(#_) }
else { die "unknown method" }
};
}
my $worker = sub {
my ($me) = #_;
my $id = $me->{id};
# $me->{foo} = "bar";
};
my $qf = Qfac($worker, [ 0 .. 10 ]);
# Send work to the thread
$qf->("enqueue", "do_something");
# ...
my $shared = $qf->("getshared");
use forks; (and its ::shared) is a drop-in replacement for use threads; (and its ::shared), and Thread::Queue uses thread::shared, so Thread::Queue will continue working just fine.
use if $ARGV[0], "forks";
use threads; # No effect under "use forks;"
use Thread::Queue;
my $q = Thread::Queue->new();
print "$$\n";
async {
print "$$\n";
print "$_\n" while $_ = $q->dequeue();
};
$q->enqueue($_) for 1..4;
$q->end();
$_->join() for threads->list();
$ perl x.pl 0
6047
6047
1
2
3
4
$ perl x.pl 1
6054
6056
1
2
3
4
(You'll need to add use forks::shared; with older versions for forks.)