מדריך לשפת התכנות - Tcl

זהו מדריך קצרצר לשפת התכנות Tcl, הוא מלמד כיצד לעבוד עם השפה ונותן רקע בסיסי למתכנתים שרוצים ללמוד אותה. Tcl היא למעשה Shell על סטרואידים ניתן להרחיב אותה בקלות עם C, והיא קלה ללמידה. זאת שפה שתיתן לכם פרוספקטיבה שונה בתור מתכנתים מפני שהיא שונה מרוב השפות שאתם מכירים.

רקע

Tcl פותחה בסוף שנות ה - 80, והיא צברה פופולריות במהרה. התחביר שלה קל ופשוט להבנה, בלי כל מיני "שטויות" או תכנוני עיצוב "מתוחכמים" ששפות מודרניות מציגות.

אם אין לכם ידע ב - Tcl, אני ממליץ לכם לקרוא את המדריך של השפה. אם אתם מעדיפים גרסה יותר קצרה תוכלו לקרוא את המדריך של antirez (הבחור שכתב את Redis) כאן. ואם אתם ממש מתעקשים, תמשיכו לקרוא את הפוסט.

אחד מהיתרונות של Tcl הוא שקל לממש את השפה, כיום המימוש הכי נפוץ (ומהיר) הוא 8.6, כל מימוש אחר של השפה כמו JimTcl יהיה יותר איטי. ולכן אני אשתמש ב - Tcl 8.6 שתוכלו להתקין עם מנהל החבילות של המערכת שלכם בקלות.

איך לקרוא את המדריך

אני משתדל לכתוב את הפוסטים שלי בצורה שתהי מובנת גם לאחרים, אני כותב בפשטות מבלי לסבך את הקוראים ולגרום לכם לאבד עניין. אם בכל זאת יש לכם שאלה לגבי הפוסט, אתם מוזמנים לשאול. כמו כן, אני מניח שלקוראים יש ידע בתכנות, עדיף ב - Shell (משתנים, לולאות, פונקציות וכ'ו).

קריאה מהנה!

בסיס

בואו נתחיל עם ה - Hello World! המסורתי, צרו קובץ בשם hello.tcl עם התוכן הבא:

puts "Hello, World!"

תריצו:

$ tclsh hello.tcl
Hello, World!

חשוב לזכור, כל דבר ב - Tcl הוא מחרוזת, לדוגמה:

set x pu
set y ts
$x$y "Hello, World!"

הפקודה set מגדירה משתנה, היא מקבלת שני ארגומנטים: שם המשתנה, והערך שלו. חשוב לזכור שבמידה והערך של המשתנה, מורכב מיותר ממילה אחת, חובה להקיף אותו במרכאות ("") או ({}), על מנת שהוא ייחשב כארגומנט בודד (בדיוק כמו בשורת הפקודה):

puts Hello, World!   # Bad
puts "Hello, World!" # Good
puts {Hello, World}  # Good

הקפה במרכאות נקראת grouping.

כפי שכבר הבנתם, השפה עובדות עם פקודות שמקבלות ארגומנטים ופרמטרים. לדוגמה אם תרצו להשתמש בפקודה puts ללא הדפסת תו שורה חדשה תעשו זאת כך:

puts -nonewline "Hello, World!"

משתנים

ב - Tcl ניתן להגדיר משתנה חדש עם הפקודה set:

set myvariable  "Hello, World!"

שם המשתנה יכול להכיל רווחים, כך תעשו זאת:

set {my variable} "Hello, World!"
puts ${my variable}

במידה ותרצו להגדיר משתנים ב - global scope, תוסיפו "::" לפני שם המשתנה:

# Bad
proc test {} {
    set xtest "Hello, World!"
}

test
puts $xtest # Error!

# Good
proc test {} {
    set ::xtest "Hello, World!"
}

test
puts $::xtest
-> Hello, World!

כאשר את מגדירים משתנים גלובלים, תמיד תגדירו אותם כמו ב האחרונה.

תגובות

כמו ב - Shell התגובות ב - Tcl מתחילות ב - #:

# This is a comment.
puts "Hello, World!"

במידה ותרצו להוסיף תגובה בסוף שורה, תעשו זאת כך:

puts "Hello, World!" ;# This is a comment.

פקודות

ניתן להריץ פקודות בכל שלב, בתוך ביטויים (בדיוק כמו ב - Shell) לדוגמה:

set name [puts John]
puts $name

set files [exec ls]
puts $files

בכדי להריץ פקודה בתוך ביטויי, הקיפו אותה ב - [ COMMAND ].

ביטויים ותנאים

ה הכי בסיסית:

if {1 == 1} {
    puts "yes"
} elseif {2 == 1} {
    puts "no"
} else {
    puts "no"
}

שימוש ב - switch:

puts -nonewline stderr "User: "
set user [gets stdin]

switch $user {
    "root" {
        puts "You can do anything."
    }
    "john" {
        puts "noop"
    }
    default {
        puts "I don't know."
    }
}

לולאות

לולאת foreach:

set mylst [glob /usr/include/*.h]

foreach item $mylst {
    puts $item
}

לולאת while:

set i 0

while {$i < 10} {
    puts $i
    set i [expr $i + 1]
}

לולאת for:

for {set x 0} {$x<10} {incr x} {
    puts "$x"
}

Procedure

על מנת להגדיר פקודה חדשה (Procedure) נשתמש בפקודה proc לדוגמה:

proc say_my_name name {
    puts "My name is: $name."
}

say_my_name John
-> My name is John

אפשר להשוות את הפקודה proc להגדרת פונקצייה חדשה בשפת תכנות סטנדרטית.

אם אתם רוצים להעביר יותר מארגומנט אחד לפקודה שלכם, תעשו זאת כך:

proc say_my_name {name age} {
    puts "Name: $name, Age: $age"
}

say_my_name "John X" 100
-> Name: John X, Age: 100

בברירת מחדל הערך שפקודה חדשה שנוצרה עם proc תחזיר, הוא הפלט של הפקודה האחרונה. לדוגמה:

proc hello {} {
    puts "Hello World"
}

set x [hello]
puts $x
-> Hello World

hello תחזיר Hello, World למרות שלא ציינו את זה עם return, ניתן להחזיר ערכים גם עם return כמובן:

proc hello {} {
    return "Hello World"
}

set x [hello]
puts $x
-> Hello World

הגדרת ערכי ברירת מחדל ל - Procedure:

proc default_name {{name John}, age} {
    puts "Name: $name, age: $age."
}

חשבון

בכדי לחשב מספרים נשתמש בפקודה expr לדוגמה:

set sum [expr 1 + 1 + 1 + 1 + [expr 13 * 10]]
puts $sum
-> 134

מחרוזות

חיבור מחרוזות עם הפקודה append:

set x "Hello, "
set y "World!"
set z [append x $y]
puts $z
-> Hello, World!

יותר קצר:

set x "Hello, "
set y "World!"
puts "$x$y"
-> Hello, World!

הפרדת מחרוזות על ידי התו \ :

set url https://bindh3x.io/file/file.txt
set file_name [lindex [split $url /] end]
puts $file_name

קבלת אורך מחרוזות:

set msg "Hello, World!"
puts [length $msg]

עבודה עם קבצים

קריאת 10 התווים הראשונים מקובץ /etc/passwd:

set fp [open /etc/passwd r]
puts [read $fp 10]
close $fp

קריאת קובץ שורה-שורה:

set fp [open /etc/passwd r]
set lines [split [read $fp] "\n"]

foreach line $lines {
    puts "LINE: $line"
}

close $fp

כתיבת המחרוזת - Hello John לקובץ hello.txt:

set fp [open hello.txt w]
puts $fp "Hello, John"
close $fp

מערך (Array)

Tcl תומכת במערכים, ניתן להגדיר אותם בצורה הבאה:

array set myarray {hello world world hello}
puts $myarray(hello)
-> world

יותר קצר:

set myarray(hello)  world
puts $myarray(hello)

הוספת איבר למערך:

array set hello {new world}
puts $hello(new)
-> world

מחיקת איבר ממערך:

array set hello {hello world}
array unset hello hello

קבלת גודל מערך:

array set hello {hello world world hello}
puts [array size hello]
-> 2

הדפסת כל האברים במערך:

array set hello {hello world world hello}

foreach {key value} [array get hello] {
    puts $value
}

רשימה (List)

יצירת רשימה והדפסת האיבר הראשון:

set mylist  "hello world world hello"
puts [lindex 0]
-> hello

חיבור שני רשימות:

set list1 "10 9 8 7 6 5"
set list2 "1 2 3 4 5"
set clist [concat $list1 $list2]

הדפסת גודל הרשימה:

set mylst "hello world"
puts [llength $mylst]
-> 2

מילון (Dict)

יצירת מילון:

dict set colors red #F44336
dict set colors blue #1976D2
dict set colors green #7CB342

הדפסת כל הערכים במילון:

dict for {name color} $colors {
    puts "name: $name, color: $value"
}

הדפסת גודל המילון:

puts [dict size $colors]
-> 3

Packages

ב - Tcl ניתן לייבא חבילות בדיוק כמו import בשפת Python, הקוד שלפניכם ידפיס את כתובת ה - IP שלכם:

package require http

::http::config -useragent "curl/7.60.0"

set token [::http::geturl http://ipinfo.io/]
set data [::http::data $token]
regexp {\d+.\d+.\d+.\d+} $data ip

puts $ip

ב השתמשנו בחבילה http שמסופקת בברירת מחדל עם Tcl 8.6.

עבודה עם קבצי הגדרות

ב - Tcl יש פקודה בשם source שמאפשרת לעשות include לקובץ (בדיוק כמו ב - Shell). ניתן לנצל את האפשרות הזאת ליצירת קובץ הגדרות לסקריפט שלנו.

לצורך ה, ניצור סקריפט שינקה את תקיית הבית שלנו מקבצים לא רצויים. צרו קובץ בשם clean.tcl עם התוכן הבא:

#!/usr/bin/env tclsh

source "$::env(HOME)/.config/clean.conf"

proc clean_log {level msg} {
    exec logger -p $level -t clean "$msg"
}

foreach f $::clean_files {
    set path $::clean_root/$f
    if {[file exists $path]} {
        clean_log info "Cleaning '$path'"
        file delete -force $path
    }
}

כפי שניתן לראות הסקריפט מקבל רשימת קבצים לניקוי מהקובץ clean.conf ומוחק אותם במידה והם קיימים.

כך יראה קובץ ה - clean.conf שלנו:

# Root directory.
set ::clean_root "$::env(HOME)"

set ::clean_files {
    .config/dconf/
    .config/procps/
    .python_history
}

תריצו את הסקריפט:

chmod +x clean.tcl
./clean.tcl

ותבדקו ב - syslog, הסקריפט ידווח אם קובץ נמחק.

סיכום

זהו עד כאן, תודה שקראתם את המדריך!