قرعه کشی کتاب «مصائب من در حباب استارتاپ»

این کتاب رو برام فرستاده بودن و خوندم و بررسی کردم و بعدش هم گفتم که اگر کسی می‌خواد صاحب بعدی‌اش باشه که درخت کمتری قطع کرده باشیم و خوشحالی بیشتری هم تولید کرده باشیم، فرمی رو پر کنه و حالا فرم پر شده و وقت قرعه‌کشی است. فرم روی گوگل بود و من csvش رو دانلود کردم:

➜  /tmp wc -l book.csv 
115 book.csv

خب ۱۱۵ نفر شرکت کننده‌داریم پس نیازمند یه عدد رندم بین ۱ تا ۱۱۵ هستیم. چیزی که خیلی‌ها توش بش بهش برنخوردن، متغیر RANDOM$ است که به شما یه عدد رندم بین ۰ تا ۳۲۷۶۷ می‌ده. ما عددی بین ۱ تا ۱۱۵ نیاز داریم پس کافیه باقیمونده‌اش به ۱۱۵ رو بگیریم (که می شه عددی بین صفر تا ۱۱۴) و بعد یکی بهش اضافه کنیم. سه بار اجراش می‌کنم و سومین عدد رو برنده اعلام می‌کنم. اینطوری تا حدی مطمئن‌تر هستم که درست کار می‌کنه:


➜ /tmp echo $((1 + $RANDOM % 115))
89
➜ /tmp echo $((1 + $RANDOM % 115))
1
➜ /tmp echo $((1 + $RANDOM % 115))
73

نفر ۷۳ برنده است. اما کیه؟ خط ۷۳ فایل رو می‌بینیم:

➜  /tmp sed -n '73p' book.csv
11/21/2020 22:19:01,y,y,y,y
➜  /tmp sed -n '1p' book.csv
11/21/2020 13:03:55,وحید,vahid*****@gmail.com,8,در یوتیوب - Vahid ****

هاه نفر ۷۳ اطلاعات الکی پر کرده بود… نفر قبل رو چک کردم و برنده کتاب مصائب من در حباب استارتاپ، وحید است (: مبارک باشه. باهات تماس می‌گیرم برای آدرس.

پروسه و برنامه تقسیم پول اینفلوئنسربازی بین فالوئرها با معکوس کردن احتمال کسانی که چند بار ثبت نام کردن

خب یادتونه که قرار شد پول اینفلوئنسر بازی رو تقسیم کنیم. اینکار رو دیشب توی یک لایو اینستاگرام کردم و حالا می خوام روشش رو به اشتراک بذارم چون بامزه بوده. اما اول سه نکته رو جواب بدم:

۱. آیا من از این طریق فالوئر جمع می کنم؟

نه. اگر می خواستم فالوئر و اینها جمع کنم باید اینطوری می گفتم که «هر کس باید من رو فالو کنه و سه تا دوستش رو زیر این پست تگ کنه تا تو مسابقه شرکت داده بشه» (: اینطوری به شکل انفجاری به صد هزار می رسیدیم منطقا ((: من اصولا دنبال فالوئر بالاتر نیستم. کیفیت بسیار مهمتره و من نه خبرگزاری هستم نه درآمدم از این راهه نه علاقمند به گروه و دسته و گنگ هستم (: همین تعداد آدم باحال بهترین چیزه.

۲. آیا بهتر نبود به خیریه بدیم؟

احتمالا چرا. شاید سری بعد اینکار رو بکنیم.

۳. ایا بهتر نبود کالا بدیم؟

اگر می شد خوب بود ولی مشکلاتی داشت. مثلا اگر می گفتم بن کتاب است بعد من باید از طرف برنده براش کتاب می خریدم پست می کردم. یا اگر می گفتم کوپن فلان جا است طرف باید حتما فلان جا عضو می شد. اینطوری ساده تر بود هرچند که خب ذات دادن پول نقد کمتر از چیزهای دیگه باحاله. در عوض طرف حق انتخاب داره (:

۴. بهتر نبود خرج جادی.نت و رادیوگیک و… بشه؟

نه. جادی.نت و رادیوگیک و هیچ چیز دیگه من در وضعیتی نیست که بشه با پول بهترش کرد (: من هر چی لازم دارم،‌ دارم و سعی می کنم ایده ام این نباشه که کارهام رو می شه با پول بیشتر بهتر کرد.


اما حدود ۴۰۰۰ نفر فرم رو پر کردن:

طبق قرار باید ۶ نفر رو به شکل رندم از بین این آدم‌ها انتخاب کنیم. اول فرم گوگل رو توی یک فایل متنی ذخیره کردم. یک ستون حاوی همه اسم ها. اسم فایل هست all.txt و می خوام پیدا کنم که اسامی تکراری چند بار تکرار شدن.

sort all.txt| uniq -c | sort -n | awk '{$1=$1};1' > counted.txt

این دستور بهمون یک فایل جدید می ده که تعدادی که هر نفر اسمش رو نوشته جلوی اسمش اومده. مثلا اینطوری:

      4 Kyarash_bordbar
      5 توییتر
      6 Mary_am_j 
     16 Kayvan_mrz
     16 اینستاگرام

اینها نفرات آخر هستن که اسمشون رو بیشتر از یکبار نوشتن. بعضی ها چیزهای بامزه نوشتن مثلا نوشتن توییتر یا انیتساگرام یا «جادی بردار برای خودت» یا «جادی بده به خیریه» و .. (: همه رو شرکت می دیم. منطقی است که شانس کسانی که یک یا دو بار اسم نوشتن مساوی باشه (تا فالو کردن در دو جا به نفع آدم ها تموم نشه) ولی کسانی که بیشتر از یک بار اسم نوشتن رو باید چیکار کنیم؟ بذارین ببینم کلا دفعات تکرار، چیا هستن:

sort all.txt| uniq -c | sort -n | awk '{$1=$1};1' | cut -f1 -d' ' | uniq 
1
2
3
4
5
6
16

یک و دو که منطقی است. ولی کسانی که ۳ تا ۶ و حتی ۱۶ بار اسم نوشتن رو چیکار کنیم؟ اینها سعی کردن شانس خودشون رو زیاد کنن پس بهتره ما شانسشون رو کم کنیم (: ایده من اینه که کسی که ۱۶ بار ثبت نام کرده یک شانزدهم بقیه شانس برنده شدن داشته باشه. اول کوچکترین مضرب مشترک این اعداد رو پیدا می کنیم:

def BMM(i, nums):
    for n in nums:
        if i%n:
            return False
    return True

i = 1
nums = [1, 2, 3, 4, 5, 6, 16]
while not BMM(i, nums):
    i += 1
print (i)

240

یعنی ما باید هر اسم رو اگر یک یا دو بار تکرار شده بود ۲۴۰ بار تکرار کنیم، اگر ۳ بار نوشته شده بود ۷۰ بار، اگر هم ۱۶ بار نوشته شده بود فقط ۱۵ بار (: شانس رو معکوس کردیم که خیلی حال می ده. بذارین برنامه اش رو بنویسیم:

import re

f = open ('/tmp/counted.txt')
o = open ('/tmp/go.txt', 'w')

for line in f:
    num, name = re.findall ('(\d+) (.*)\n', line)[0]
    if num == '2':
        num = 1
    for i in range(0, 240/int(num)):
        o.write(name+'\n')

حالا ما یک فایل داریم که اگر توش کسی ۱۶ بار ثبت نام کرده، اسمش ۱۵ بار اومده، اگر کسی یک یا دو بار ثبت نام کرده اسمش ۲۴۰ بار اومده! شانس ها معکوس شد. حالا وقت قرعه کشی است:

import random
lines = open('/tmp/go.txt').read().splitlines()
myline =random.choice(lines)
print(myline)

هر بار که این رو اجرا کنیم یه اسم به ما می ده و با چک کردن دستی معلوم می شد که توی اینستاگرام بوده یا توییتر یا جای دیگه و بهش مسیج می دادم و برنده بودنش رو اعلام می کردم! بامزه و فان و راحت و سریع با پایتون باحال.

تغییر فرمت کلی عکس با کامند لاین

دوستی پرسیده چطور می تونه ده تا عکس با فرمت jpg رو از طریق کامند لاین به png تبدیل کنه. بذارین با هم پیش بریم. اول یک دایرکتوری می سازم که بتونیم توش کار کنیم:

➜  /mkdir /tmp/jpg2png
➜  /cd /tmp/jpg2png 
➜  jpg2png

حالا باید ده تا عکس جی پگ اتفاقی از کامپیوتر پیدا کنم. یک دستور بامزه هست که هم فایل ها با پسوند جی پی گ رو نشون می ده؛ البته در یک دایرکتوری خاص که اینه:

find ~/Pictures -iname '*jpg'

کافیه کل خروجی ها رو به شکل رندم مرتب کنیم:

find ~/Pictures -iname '*jpg' | sort --random-sort

که البته چون روی مک هستیم که توش یکی تصمیم گرفته sort استاندارد گنو رو بیخیال بشه و یک سورت ناقص تحویلمون بده، باید از سورت گنو که با برو نصب شده استفاده کنم، یعنی:

find ~/Pictures -iname '*jpg' | gsort --random-sort

و اگر ده تا اولی رو پیدا کنیم، یعنی ده تا فایل اتفاقی از دایرکتوری عکس ها ریختم .. نه.. باید بریزیمش… پس می دیم به ایکس آرگز:

find ~/Pictures -iname '*jpg' | gsort --random-sort | head -10 | xargs -I files cp files .

و البته مک یک انگولک مسخره هم به xargs کرده ولی به هرحال کار می کنه. در واقع ظاهرا دیفالتش یک -L 1 داره! حالا ما ده تا فایل اتفاقی جی پگ داریم:

➜  jpg2png ls
33_ibm7291.jpg
IMG_0104.jpg
IMG_20140910_090542.jpg
IMG_20150101_144039.jpg
IMG_20150607_084842.jpg
IMG_20150617_210638.jpg
IMG_20150721_214643.jpg
JungfrauClimbers_EN-US11631578069_1366x768.jpg
MaracanaFireworks_EN-US9834580695_1366x768.jpg
dual_grass.jpg

حالا کافیه با استفاده از برنامه imagemagick که همیشه نصب داریمش (توی اوبونتو با apt install و در مک با brew install) بریم سراغ درست کردن یک دایرکتوری برای پی ان جی ها، و ساختن خروجی ها با یک حلقه فور که روی هر فایل یک دستور convert اجرا می‌کنه:

➜  mkdir pngs
➜  for file in *.jpg; do convert $file pngs/$file.png  ; done

و همه چیز مرتب شده:

➜  tree
zsh: command not found: tree
➜  brew install tree
Updating Homebrew...
==> Auto-updated Homebrew!
Updated 1 tap (homebrew/core).
==> New Formulae
exa             httpflow        jvm-mon         libetpan        terraform-docs
==> Updated Formulae
amazon-ecs-cli  g3log           lynis           paket           terraform
ats2-postiats   geoip           macvim          ponyc           todolist
aws-sdk-cpp     git-lfs         media-info      roswell         urh
awscli          github-release  mediaconch      rtv             uwsgi
clutter-gst     jenkins-lts     metabase        ruby@2.3        vim
convox          jfrog-cli-go    node ✔          scw             vnu
crystax-ndk     jmxtrans        opensc          sqlite ✔
fdroidserver    khal            osmfilter       swiftformat
fluent-bit      kobalt          osrm-backend    sysdig
==> Deleted Formulae
dwarf-fortress             fb-adb                     multirust

==> Downloading https://homebrew.bintray.com/bottles/tree-1.7.0.sierra.bottle.1.

curl: (7) Failed to connect to homebrew.bintray.com port 443: Operation timed out
Error: Failed to download resource "tree"
Download failed: https://homebrew.bintray.com/bottles/tree-1.7.0.sierra.bottle.1.tar.gz
Warning: Bottle installation failed: building from source.
==> Using the sandbox
==> Downloading http://mama.indstate.edu/users/ice/tree/src/tree-1.7.0.tgz
######################################################################## 100.0%
==> make prefix=/usr/local/Cellar/tree/1.7.0 MANDIR=/usr/local/Cellar/tree/1.7.0
?  /usr/local/Cellar/tree/1.7.0: 8 files, 114.3KB, built in 5 seconds
➜  tree
.
├── 33_ibm7291.jpg
├── IMG_0104.jpg
├── IMG_20140910_090542.jpg
├── IMG_20150101_144039.jpg
├── IMG_20150607_084842.jpg
├── IMG_20150617_210638.jpg
├── IMG_20150721_214643.jpg
├── JungfrauClimbers_EN-US11631578069_1366x768.jpg
├── MaracanaFireworks_EN-US9834580695_1366x768.jpg
├── dual_grass.jpg
└── pngs
    ├── 33_ibm7291.jpg.png
    ├── IMG_0104.jpg.png
    ├── IMG_20140910_090542.jpg.png
    ├── IMG_20150101_144039.jpg.png
    ├── IMG_20150607_084842.jpg.png
    ├── IMG_20150617_210638.jpg.png
    ├── IMG_20150721_214643.jpg.png
    ├── JungfrauClimbers_EN-US11631578069_1366x768.jpg.png
    ├── MaracanaFireworks_EN-US9834580695_1366x768.jpg.png
    └── dual_grass.jpg.png

1 directory, 20 files

می‌بینین که برای کار به مک برگشتم. بعدا دلایلش رو می نویسم ولی خلاصه اش اینه که شرکت استانداردش مک است و تجربه هم می شه. از اونطرف نکته جالبتر اینه که در واقع می بینین وقتی می گیم گنو/لینوکس چقدر تاکیدمون روی بخش گنو زیاده. در اصل این ابزارهای باحال مربوط به پروژه گنو است و در نتیجه سیستم هایی که پایه گنو/یونیکسی دارن هم ازش لذت می برن. مثلا همین مک. و از اونطرف راحت می بینین که چرا مک رو اعصاب می ره،‌ مثلا دستوری به خوبی سورت رو برداشته فلج کرده هرچند که با پروژه فوق العاده هوم‌برو، تقریبا همه چیزهای مهم لینوکس رو می شه اینطرف هم داشت، به جز یک رابطه کاربری کارا و خوش دست و یه ادیتور فارسی متن محض درست – بعدا در موردش بیشتر حرف می زنیم (:

درست کردن خودکار فهرست فایل های دایرکتوری

یک ایمیل داشتیم که درخواست می کرد دایرکتوری audio توی سرور من قابل خوندن باشه که بشه یک ضرب کل رادیو گیک ها رو ازش گرفت. اینکار رو می شه با باز گذاشتن اتوایندکس درست کرد که معمولا کار خوبی نیست یا می شه یک اسکریپت کوچیک براش نوشت. اینطوری:

اگر نمی خواین ۱۲ دقیق ویدئو رو ببینین، خلاصه اش اینه که یک اسکریپت ساده به این شکل فایل اچ تی ام ال مورد نظر رو تولید می کنه :

#!/bin/sh

cd /home/jadi/public_html/audio/
echo "<html><body>" > index.html
echo "<ul>" >> index.html

for i in `ls *mp3 -tr`
do
    echo "<li>" >> index.html
    echo \<a href="$i"\>$i\</a\> >> index.html
    echo \</li\> >> index.html
done
echo "</ul>" >> index.html
echo "</body></html>" >> index.html

و کافیه این رو توی کرون بذاریم تا هر روز یکبار اجرا بشه:

07  12  *   *   *   /home/jadi/public_html/audio/makeindex.sh

و حالا می تونین مستقیم دایرکتوری http://jadi.net/audio رو ببینین؛ البته اگر شما هم می خواین دانلود کنین اجازه بدین یک کم زمان بگذره که همه با هم مشغول گرفتن اینهمه فایل نباشیم (:

اشتباه زدم، فاک!

سعید توی کامنتش در مطلب خداحافظ شل، سلام زیشل، یه برنامه جالب معرفی کرده: د فاک. این برنامه بامزه دقیقا همونی است که بعضی‌هامون وقتی یک تیکه از یک کامند رو اشتباه می‌زنیم می‌گیم: «د فاک/چرا اجرا نشد؟». اگر درست بعد از اون کامند بزنین fuck خودش می‌فهمه مشکل دستور قبلی است، سعی می کنه تصحیحش کنه و با یک انتر شما، اجراش کنه. مثلا:

برنامه با پایتون است و برای نصبش کافیه بزنین:

sudo -H pip install thefuck

و بعد از اولین fuck، خودش راهنمایی می کنه که چی رو باید کجا بنویسین. احتمالا یک کد کوتاه رو در bashrc. یا zshrc. و بعد اجرای دوباره bash یا zsh.

چرا گنو/لینوکس رو دوست دارم: بررسی اسم رنگ های فارسی

بحث از جای جالبی شروع شد. من گفتم رنگ های ایرانی بامزه هستن چون موارد خیلی کمی داریم که توش یک اسم خاص برای یک رنگ استفاده شده باشه. مثلا «زرد» یک اسم خاص است که به یک رنگ اشاره می‌کنه ولی «آبی» یعنی چیزی که به رنگ آب است. برای بررسی این نسبت، سری به صفحه رنگ های ویکیپدیا زدم و بعد از حذف رنگ‌های تفسیری (خودم اسم می ذارم دیگه!) یعنی مثلا «سبز لجنی» یا «آبی درباری» و حذف پسوندهایی مثل «تیره» و «سیر» و … و موارد مشابه به این هشتاد و یک رنگ رسیدم:

آبی، آجری، آل، آلبالویی، اُخرایی، ارغوانی، استخوانی، بادمجونی، برگ سنجدی، برنجی، برنزی، بژ، بنفش، پرکلاغی، پوست پیازی، پوست گرگی، تاج خروسی، تریاکی، جگری، حنایی، خاکستری، خاکی، خردلی، خرمایی، دارچینی، دودی، دوغی، دلفینی، روناسی، زرد، زرشکی، زعفرانی، زغالی، زیتونی، سبز، سدری، سربی، سرخ، سرخابی، سرمه‌ای، سفید، سیاه، مشکی، شرابی، شفقی، شکلاتی، شنگرفی، شیرشکری، شیری، صورتی، طلایی، طوسی، عنابی، فندقی، فولادی، فیروزه‌ای، فیلی، قرمز، قهوه‌ای، کرم، کله غازی، گردویی، گلبهی، گیلاسی، لاجوردی، لجنی، لیمویی، ماشی، مرجانی، مسی، مغزپسته‌ای، نارنجی، نخودی، نقره‌ای، نوک مدادی، نیلی، هلویی، یاسی، یاقوتی، یخی، یشمی

هوم.. برنامه یا دست؟ برنامه.. هر چی باشه ما هکریم! بذارین آخر هر چیزی که «ی» هست رو بشمریم و نگاهی بندازیم که اشتباه نشده باشه:

jadi@funlife:/tmp$ grep ".*ی$" colors.txt  | wc -l 
71

jadi@funlife:/tmp$ grep ".*ی$" colors.txt  | xargs echo | sed 's/ /، /g'
آبی، آجری، آلبالویی، اُخرایی، ارغوانی، استخوانی، بادمجونی، برگ سنجدی، برنجی، برنزی، پرکلاغی، پوست پیازی، پوست گرگی، تاج خروسی، تریاکی، جگری، حنایی، خاکستری، خاکی، خردلی، خرمایی، دارچینی، دودی، دوغی، دلفینی، روناسی، زرشکی، زعفرانی، زغالی، زیتونی، سدری، سربی، سرخابی، سرمهای، مشکی، شرابی، شفقی، شکلاتی، شنگرفی، شیرشکری، شیری، صورتی، طلایی، طوسی، عنابی، فندقی، فولادی، فیروزه ای، فیلی، قهوه ای، کله غازی، گردویی، گلبهی، گیلاسی، لاجوردی، لجنی، لیمویی، ماشی، مرجانی، مسی، مغزپسته ای، نارنجی، نخودی، نقره ای، نوک مدادی، نیلی، هلویی، یاسی، یاقوتی، یخی، یشمی


jadi@funlife:/tmp$ grep -v ".*ی$" colors.txt  | wc -l 
10

jadi@funlife:/tmp$ grep -v ".*ی$" colors.txt  | xargs echo | sed 's/ /، /g'
آل، بژ، بنفش، زرد، سبز، سرخ، سفید، سیاه، قرمز، کرم
jadi@funlife:/tmp$ 

خب.. ده تا رنگ داریم که به چیزی اشاره نمی‌کنن و خودشون هستن:

‌ آل، بژ، بنفش، زرد، سبز، سرخ، سفید، سیاه، قرمز، کرم

در اینجا «آل» یک جور قرمز است و بقیه هم که مشخصن. پس از بین ۸۱ رنگی که داشتیم،‌ ده رنگ اسم خاص خودشون رو دارن و ۷۱ رنگ به چیزهای مختلف برای توضیح رنگ ها اشاره می کنن.

colors

و نکات جالب؟

  • رنگ های باحالی داریم مثل دوغی، یخی، دودی و البته تریاکی!
  • سفید یخچالی جزو رنگ ها است که البته اینجا نشمردیم چون بخشی از «سفید» است ولی جالبه که قبل از ورود یخچال به اون رنگ چی می گفتن
  • من همیشه به شوخی از آدم ها می پرسیدم کدوم رنگ است که فقط به چشم اشاره می کنه و نه چیز دیگه! جواب «میشی» است.. ظاهرا دلیلش اینه که کلا «میشی» اسم رنگ نیست و اشتباه مصطلح است. رنگ درست «ماشی» است (:
  • نوک مدادی هم بامزه است (در کنار قرمز ماتیکی یا کالباسی مثلا!) چون منطقا این چیزها خودوشن نیازمند تفسیر شدن رنگ هستن. یعنی خود مداد رو باید بگیم چه رنگیه بعد بگیم اون رنگ رنگ مداده (:

راستی! معلومه که فرض اولیه این مطلب وقتی منطقی می شه که با بقیه زبون‌ها هم مقایسه کنیم ولی خب در همین حد برای من فان بوده (:

چرا گنو/لینوکس رو دوست دارم:‌ فهرست کردن کل فایل‌های قابل دانلود یک سایت

یک دوستی پرسیده که چطوری می تونیم فهرست همه فایل‌های قابل دانلود در سروری مثل dl.folan.net رو داشته باشیم. این سرور اجازه می‌ده شما دایرکتوری‌هاش رو ببینین:

Screenshot from 2015-11-25 11-57-46

و مثلا توی دایرکتوری فیلم‌ها:

Screenshot from 2015-11-25 11-58-08

درست؟ دوست همیشگی ما در سری چرا گنو/لینوکس رو دوست دارم دستور جذاب wget است. پس شروع می کنیم!

$ wget --spider --force-html -r -l5 htp://dl.folan.net/Movie/

می تونه به شکل یک اسپایدر فایل‌های اچ تی ام ال رو می‌گیره و توشون رو نگاه می کنه و پاک می کنه و اینکار رو تا پنج شاخه داخل دایرکتوری‌ها هم پی‌ می‌گیره. البته اگر ارور بگیریم، دردسر درست می‌شه پس با اضافه کردن یک عبارت کوچیک، ارورها رو هم به خروجی اضافه می کنیم:

$ wget --spider --force-html -r -l5 htp://dl.folan.net/Movie/ 2>&1 

این دستور خروجی‌هایی شبیه به این تولید می کنه:

Spider mode enabled. Check if remote file exists.
--2015-11-25 12:02:51--  htp://dl.folan.net/Movie/5/American.History.X.1998.720p.folan.Net.mkv
Reusing existing connection to dl.folan.net:80.
htp request sent, awaiting response... 200 OK
Length: 785963069 (750M) [application/octet-stream]
Remote file exists but does not contain any link -- not retrieving.

Removing dl.folan.net/Movie/5/American.History.X.1998.720p.folan.Net.mkv.
unlink: No such file or directory

Spider mode enabled. Check if remote file exists.
--2015-11-25 12:02:51--  htp://dl.folan.net/Movie/5/American.Justice.2015.1080p.folan.Net.mkv
Reusing existing connection to dl.folan.net:80.

من خط‌هایی رو می‌خوام که اولشون — داره و پس می ریم سراغ grep که می‌تونه توی یک متن خط‌هایی رو جدا کنه که چیز خاصی توشون هست:

$ wget --spider --force-html -r -l5 htp://dl.folan.net/Movie/ 2>&1 | grep '^--'
--2015-11-25 12:04:57--  htp://dl.folan.net/Movie/4/A.Good.Day.to.Die.Hard.2013.720p.folan.Net.mkv
--2015-11-25 12:04:57--  htp://dl.folan.net/Movie/4/A.Good.Marriage.2014.BluRay.720p.folan.Net.Mkv
--2015-11-25 12:04:57--  htp://dl.folan.net/Movie/4/A.Hijacking.2012.720p.folan.Net.mkv

و خب حالا می تونیم فقط بخش یو آر ال رو جدا کنیم. با استفاده از awk:

$ wget --spider --force-html -r -l5 htp://dl.folan.net/Movie/ 2>&1 | grep '^--' | awk '{ print $3 }' 
htp://dl.folan.net/6piljd5xepub7trr13ke.gif
htp://dl.folan.net/85film3.gif
htp://dl.folan.net/Movie/1/Into.the.Woods.2014.720p.%5Bfolan.Net%5D.mkv
htp://dl.folan.net/Movie/1/Iyobinte.Pusthakam.2014.720p.DVDrip.%5Bfolan.Net%5D.mp4
htp://dl.folan.net/Movie/1/Kick.2014.720p.BluRay.%5Bfolan.Net%5D.mkv
htp://dl.folan.net/Movie/1/La.Grande.Illusion.1937.720p.Farsi.Dubbed.%5Bfolan.Net%5D.mkv
htp://dl.folan.net/Movie/1/Late.Phases.2014.720p.%5Bfolan.Net%5D.mkv
htp://dl.folan.net/Movie/1/Le-Week-End.720p.%5Bfolan.net%5D.mkv
htp://dl.folan.net/Movie/1/Legendary.2010.LIMITED.720p.%5Bfolan.Net%5D.mkv

و بعد فقط خط‌هایی رو نگه داریم که آخرشون چیزهایی مثل / یا css یا html و .. نداره:

$ wget --spider --force-html -r -l5 htp://dl.folan.net/Movie/ 2>&1 | grep '^--' | awk '{ print $3 }' | grep -v '\.\(css\|js\|png\|gif\|jpg\)$' | grep -v '\/$' 
htp://dl.folan.net/Movie/1/Into.the.Woods.2014.720p.%5Bfolan.Net%5D.mkv
htp://dl.folan.net/Movie/1/Iyobinte.Pusthakam.2014.720p.DVDrip.%5Bfolan.Net%5D.mp4
htp://dl.folan.net/Movie/1/Kick.2014.720p.BluRay.%5Bfolan.Net%5D.mkv
htp://dl.folan.net/Movie/1/La.Grande.Illusion.1937.720p.Farsi.Dubbed.%5Bfolan.Net%5D.mkv
htp://dl.folan.net/Movie/1/Late.Phases.2014.720p.%5Bfolan.Net%5D.mkv
htp://dl.folan.net/Movie/1/Le-Week-End.720p.%5Bfolan.net%5D.mkv
htp://dl.folan.net/Movie/1/Legendary.2010.LIMITED.720p.%5Bfolan.Net%5D.mkv

ایول. حالا کافیه همه چیز رو بریزیم توی یک فایل و خروی‌ها رو یک چکی بکنیم که درست باشه:

$ sort -R all.urls | head
htp://dl.folan.net/Movie/5/Modern.Times.1936.720p.Farsi.Dubbed.folan.Net.mkv
htp://dl.folan.net/Serial/The%20Killing/S01/The.Killing.S01E08.480p.folan.Net.mkv.folan.Net.mkv.mkv
htp://dl.folan.net/Serial/Breaking%20Bad/S05/BreakingBad.S05E06.folan.Net.mkv
htp://dl.folan.net/Movie/2/Priest.of.Evil.2010.720p.%5Bfolan.Net%5D.mkv
htp://dl.folan.net/Movie/5/A.Midsummer.Nights.Dream.1999.720p.WEB-DL.folan.Net.mkv
htp://dl.folan.net/Serial/Castle/S05/Castle.S05E22.480p.folan.Net.mkv
htp://dl.folan.net/Serial/Twin%20Peaks/S02/Twin.Peaks.S02E22.480p.folan.Net.mkv
htp://dl.folan.net/Serial/Supernatural/S04/SN-S04_E11.folan.Net.mkv
htp://dl.folan.net/Movie/Problem%20Child%201990/Bacheye.DardesarSaz.1990.720pWEB-DL.HQ_folan.info.mkv
htp://dl.folan.net/Serial/Archer/S01/Archer.S01E08.folan.Net.mkv

$ wc -l all.urls 
11284 all.urls

اینجوری فهرستی از ۱۱هزار فایل قابل دانلود اون سایتی که تصمیم گرفتم به خاطر حفظ بیزنسش، آدرسش رو ندم رو داشته باشیم (: هدف این پست دانلود نیست،‌ یاد گرفتن شیوه کار با لینوکسه و همچنین دقت کنین که http ها رو کردم htp که وبلاگ سعی نکنه به عنوان فیلم لودشون کنه از یو آر ال گفته شده (: خوش باشین و خندون و توانمند.

چرا گنو لینوکس رو دوست دارم: پاسخ دادن به اینکه آیا سیستم ما وضعیت عادی داره یا مورد حمله است

ما سروری داریم که تازه تحویلش دادیم ولی هر روز حوالی ظهر با مشکل مواجه می شه. کار اصلی رو پروسه ای انجام می ده که اینجا بهش می گیم A. چندین پروسه A می تونن همزمان بالا باشن و کار کنن و ما گفتیم حداکثر این تعداد باید ۱۰۰ باشه. یعنی در صورت زیاد شدن بار، ۱۰۰ تا A بالا می یان و تقریبا صد برابر بهتر از یک A کار می کنن. یک بررسی سریع نشون می ده که در لحظه بروز مشکل دقیقا ۱۰۰ تا از پروسه A فعاله:

# ps -ef | grep A | wc -l
101

مشخصه دیگه: ps -ef پروسه ها رو نشون می ده، grep A فقط خط هایی که توشون A هست رو جدا می کنه و در نهایت wc -l تعداد خط ها رو می شمره (اگر گفتین چرا به جای ۱۰۰ تا شده صد و یکی؟).

علی الحساب تعداد Aها رو به حداکثر ۱۰۰۰ عدد افزایش می دیم و می ریم سراغ سوالی که مطرحه:

آیا ما مورد حمله هستیم؟ آیا حوالی ظهر سیستمی شروع به کار با سیستم ما می کنه که فشار رو به شکل غیرعادی بالا می بره؟ یا واقعا این شرایط عادی است و اینقدر از این سیستم استفاده می شه؟

ما لاگ هایی به این شکل داریم که حاصل کار A هستن:

127.0.0.1 -  26/Jul/2015:03:48:53 +0430 "POST /index.php?_url=xxxxx" 200 /home/adp/www/xxx/public/index.php 357.489 2048 86.72%
127.0.0.1 -  26/Jul/2015:03:48:58 +0430 "POST /index.php?_url=qqqq" 200 /home/adp/www/xxx/public/index.php 91.281 1280 98.60%
127.0.0.1 -  26/Jul/2015:03:49:32 +0430 "GET /index.php?aaa" 200 /home/adp/www/xxx/public/index.php 373.649 1792 56.20%
127.0.0.1 -  26/Jul/2015:03:50:03 +0430 "HEAD /index.php" 200 /home/adp/www/xxx/public/index.php 43.501 1280 91.95%
127.0.0.1 -  26/Jul/2015:03:55:03 +0430 "HEAD /index.php" 200 /home/adp/www/xxxx/public/index.php 63.519 1280 94.46%

من از چند روز پیش این لاگ ها رو فعال کردم تا همه درخواست ها ذخیره بشن و حالا کافیه بشمرم ببینم چه خبره! اول بذارین همه لاگ هار و به همدیگه بچسبونیم:

jadi@funlife:/tmp/dir$ ls -ltrh 
total 36M
-rw------- 1 jadi jadi 9.2M Jul 22 03:17 www.access.log-20150722
-rw------- 1 jadi jadi 6.0M Jul 23 03:10 www.access.log-20150723
-rw------- 1 jadi jadi 6.4M Jul 24 03:25 www.access.log-20150724
-rw------- 1 jadi jadi 2.5M Jul 25 03:25 www.access.log-20150725
-rw------- 1 jadi jadi 7.4M Jul 26 03:45 www.access.log-20150726
-rw------- 1 jadi jadi 4.2M Jul 26 15:17 www.access.log
jadi@funlife:/tmp/dir$ cat www.access.log-* www.access.log > all.log
jadi@funlife:/tmp/dir$ ls -ltrh 
total 72M
-rw------- 1 jadi jadi 9.2M Jul 22 03:17 www.access.log-20150722
-rw------- 1 jadi jadi 6.0M Jul 23 03:10 www.access.log-20150723
-rw------- 1 jadi jadi 6.4M Jul 24 03:25 www.access.log-20150724
-rw------- 1 jadi jadi 2.5M Jul 25 03:25 www.access.log-20150725
-rw------- 1 jadi jadi 7.4M Jul 26 03:45 www.access.log-20150726
-rw------- 1 jadi jadi 4.2M Jul 26 15:17 www.access.log
-rw-rw-r-- 1 jadi jadi  36M Jul 26 15:30 all.log

راحت و سر راست. دستور cat که محتوای فایل ها رو نشون می ده، کل فایل ها رو چسبونده به هم تا یک فایل بزرگ به اسم all.log داشته باشیم که هر خطش چنین فرمی داره:

127.0.0.1 -  26/Jul/2015:03:48:53 +0430 "POST /index.php?_url=xxxxx" 200 /home/adp/www/xxx/public/index.php 357.489 2048 86.72%

کافه من تاریخ رو جدا کنم. دستور کات همیشه دوست منه:

jadi@funlife:/tmp/dir$ cut -d' ' -f4 all.log | head
20/Jul/2015:12:03:35
20/Jul/2015:12:03:36
20/Jul/2015:12:03:39
20/Jul/2015:12:03:39

جذاب نیست؟ به سادگی گفتم کات کن با جدا کننده اسپیس و فیلد چهارم رو به من بده ولی حالا فقط چند خط اول رو نشون بده (head). عملا کار تموم شده! کافیه این خطها رو بشمرم؛ البته بعد از حذف کردن ثانیه و دقیقه. برای حذف اینها کافیه شش کاراکتر آخر هر خط رو بردارم یا با همون دستور کات دوباره بگم بر اساس :‌ جدا کنه و فیلد اول و دوم رو به من بده. این راه دوم برای من سر راست تره:

jadi@funlife:/tmp/dir$ cut -d' ' -f4 all.log | cut -d: -f1,2 | head
20/Jul/2015:12
20/Jul/2015:12
20/Jul/2015:12
20/Jul/2015:12
20/Jul/2015:12
20/Jul/2015:12
20/Jul/2015:12
20/Jul/2015:12
20/Jul/2015:12
20/Jul/2015:12

چقدر عالی. دیگه فقط کافیه سورت کنیم و بگیم بشمره. دستور uniq‌ می تونه با سوییچ های مختلف کارهای مختلف کنه. مثلا فقط خط های غیرتکراری بده، فقط خط های تکراری رو بده، از هر خط بیشتر از یکبار نده، بشمره از هر خط چند تا هست و … و البته این دستور وابسته به اینه که ورودی اش مرتب شده باشه. پس:

jadi@funlife:/tmp/dir$ cut -d' ' -f4 all.log | cut -d: -f1,2 | sort -n | uniq -c > data
jadi@funlife:/tmp/dir$ head data
   2795 20/Jul/2015:12
   2363 20/Jul/2015:13
   2383 20/Jul/2015:14
   2251 20/Jul/2015:15
   1796 20/Jul/2015:16
   1599 20/Jul/2015:17
    843 20/Jul/2015:18
    704 20/Jul/2015:20
    765 20/Jul/2015:19
   1039 20/Jul/2015:21

چه کردیم! (: فقط کافیه ترسیمش کنیم:

تعداد درخواست های سرور

و هر کسی که آمار یا حداقل نمودارهای نرمال بدونه می تونه بگه اتفاق غیرعادی ای در جریان نیست – حداقل در سطح درخواست ها. از ساعت هشت درخواست ها بالا می رن و بعد به شکلی نسبتا طبیعی افزایش پیدا می کنن تا آخر وقت اداری که دوباره آروم آروم پایین بیان. این پترن برای سایتی که مردم باهاش کار می کنن طبیعی است. مطمئنا می شه برنامه ما رو بهتر کرد ولی هدف من به عنوان مدیر سیستم این هست و بود که نشون بدم اتفاقی غیر عادی (درخواست ناگهانی از یک سیستم سر یک ساعت مشخص، حمله هکرها و …) در جریان نیست که تقریبا ثابت شده. اگر نمودارهای این تیپی دوست دارین بگین که بازم نمودارهایی واقعی از کارهای واقعی یک مدیر سیستم رو با هم مرور کنیم.