Saturday, 28 November 2015

FUSE, FUSEEETTT DAH

FUSE adalah Filesystem in Userspace, dengan FUSE kita dapat membuat filesystem kita sendiri dengan aturan yang kita inginkan.

Untuk menggunakan fuse, kita harus menginstallnya terlebih dahulu, kalian bisa mendownload file untuk fuse di

1. http://fuse.sourceforge.net/
2. Extract ke folder yang kalian inginkan.
3. Masuk ke folder hasil extraction melalui terminal
4. Ganti hak ases super user
5. ketik ./configure
6. ketik make
7. ketik make install

setelah itu fuse dapat digunakan.

Jadi bagaimana kita memodifikasi dalam fuse?

Didalam fuse terdapat beberapa fungsi dimana fungsi tersebut berguna untuk mengatur hal hal yang berhubungan dengan filesystem buatan kita sendiri ini.

fungsi yang bisa dimodifikasi yang tersedia di fuse ada dibawah ini:
struct fuse_operations {
    int (*getattr) (const char *, struct stat *); 
    int (*readlink) (const char *, char *, size_t);
    int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
    int (*mknod) (const char *, mode_t, dev_t);
    int (*mkdir) (const char *, mode_t);
    int (*unlink) (const char *);
    int (*rmdir) (const char *);
    int (*symlink) (const char *, const char *);
    int (*rename) (const char *, const char *);
    int (*link) (const char *, const char *);
    int (*chmod) (const char *, mode_t);
    int (*chown) (const char *, uid_t, gid_t);
    int (*truncate) (const char *, off_t);
    int (*utime) (const char *, struct utimbuf *);
    int (*open) (const char *, struct fuse_file_info *);
    int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info *);
    int (*write) (const char *, const char *, size_t, off_t,struct fuse_file_info *);
    int (*statfs) (const char *, struct statfs *);
    int (*flush) (const char *, struct fuse_file_info *);
    int (*release) (const char *, struct fuse_file_info *);
    int (*fsync) (const char *, int, struct fuse_file_info *);
    int (*setxattr) (const char *, const char *, const char *, size_t, int);
    int (*getxattr) (const char *, const char *, char *, size_t);
    int (*listxattr) (const char *, char *, size_t);
    int (*removexattr) (const char *, const char *);
};
Berikut ini adalah contoh penggunaan fuse untuk filesystem yang apabila suatu file dicopy maka file asli akan di lock (tidak dapat dibuka atau di copy lagi)


#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <sys/statfs.h>
#include <stdlib.h>


static const char *dirpath = "/home/ariobimo/Documents";
char simpen[1000];

static int xmp_getattr(const char *path, struct stat *stbuf)
{
    int res;
    char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,path);
    res = lstat(fpath, stbuf);
    if(res == -1)
        return -errno;

    return 0;
}

static int xmp_readlink(const char *path, char *buf, size_t size)
{
    int res;
    char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,path);
    res = readlink(fpath, buf, size - 1);
    if(res == -1)
        return -errno;

    buf[res] = '\0';
    return 0;
}


static int xmp_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler)
{
    DIR *dp;
    struct dirent *de;
    int res = 0;
    char fpath[1000];
  
 if(strcmp(path,"/") == 0)
    {
        path=dirpath;
        sprintf(fpath,"%s",path);
    }
    else sprintf(fpath, "%s%s",dirpath,path);

    dp = opendir(path);
    if(dp == NULL)
        return -errno;

    while((de = readdir(dp)) != NULL) {
        res = filler(h, de->d_name, de->d_type);
        if(res != 0)
            break;
    }

    closedir(dp);
    return res;
}



static int xmp_mkdir(const char *path, mode_t mode)
{
    int res;
    char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,path);
    res = mkdir(fpath, mode);
    if(res == -1)
        return -errno;

    return 0;
}

static int xmp_unlink(const char *path)
{
    int res;
char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,path);
    res = unlink(fpath);
    if(res == -1)
        return -errno;

    return 0;
}

static int xmp_rmdir(const char *path)
{
    int res;
char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,path);
    res = rmdir(fpath);
    if(res == -1)
        return -errno;

    return 0;
}

static int xmp_symlink(const char *from, const char *to)
{
    int res;
char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,from);
char fpath2[1000];
    sprintf(fpath2,"%s%s",dirpath,to);
    res = symlink(from, to);
    if(res == -1)
        return -errno;

    return 0;
}

static int xmp_rename(const char *from, const char *to)
{
    int res;
    char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,from);
    char fpath2[1000];
    sprintf(fpath2,"%s%s",dirpath,to);
    res = rename(fpath, fpath2);
    if(res == -1)
        return -errno;

    return 0;
}

static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
{
    int res;
    char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,path);
    res = mknod(fpath,mode,rdev);
    if(res == -1)
        return -errno;

  
    return 0;
}

static int xmp_link(const char *from, const char *to)
{
    int res;
char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,from);
char fpath2[1000];
    sprintf(fpath2,"%s%s",dirpath,to);
    res = link(fpath, fpath2);
    if(res == -1)
        return -errno;

    return 0;
}

static int xmp_chmod(const char *path, mode_t mode)
{
    int res;
    char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,path);
    res = chmod(fpath, mode);
    if(res == -1)
        return -errno;
   
    return 0;
}

static int xmp_chown(const char *path, uid_t uid, gid_t gid)
{
    int res;
char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,path);
    res = lchown(fpath, uid, gid);
    if(res == -1)
        return -errno;

    return 0;
}

static int xmp_truncate(const char *path, off_t size)
{
    int res;
    char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,path);
    res = truncate(fpath, size);
    if(res == -1)
        return -errno;

    return 0;
}

static int xmp_utime(const char *path, struct utimbuf *buf)
{
    int res;
    char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,path);
    res = utime(fpath, buf);
    if(res == -1)
        return -errno;

    return 0;
}


static int xmp_open(const char *path, int flags)
{
    int res;
    char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,path);
    res = open(fpath, flags);
    if(res == -1)
        return -errno;

    close(res);
    return 0;
}

static int xmp_read(const char *path, char *buf, size_t size, off_t offset)
{
    int fd;
    int res;
    char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,path);
    strcpy(simpen,path);
    fd = open(fpath, O_RDONLY);
    if(fd == -1)
        return -errno;

    res = pread(fd, buf, size, offset);
    if(res == -1)
        res = -errno;
   
    close(fd);
    return res;
}

static int xmp_write(const char *path, const char *buf, size_t size,
                     off_t offset)
{
    int fd;
    int res;
    char fpath[1000];
    char something[1000];
    sprintf(fpath,"%s%s",dirpath,path);
    fd = open(fpath, O_WRONLY);
    if(fd == -1)
        return -errno;
   sprintf(something,"%s%s",dirpath,simpen);
   chmod(something,0000);
    res = pwrite(fd, buf, size, offset);
    if(res == -1)
        res = -errno;
 
    close(fd);

    return res;
}

/*static int xmp_statfs(struct fuse_statfs *fst)
{
    struct statfs st;
    int rv = statfs("/",&st);
    if(!rv) {
        fst->block_size  = st.f_bsize;
        fst->blocks      = st.f_blocks;
        fst->blocks_free = st.f_bavail;
        fst->files       = st.f_files;
        fst->files_free  = st.f_ffree;
        fst->namelen     = st.f_namelen;
    }
    return rv;
}*/

static int xmp_release(const char *path, int flags)
{
    /* Just a stub.  This method is optional and can safely be left
       unimplemented */
    char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,path);
    (void) fpath;
    (void) flags;
    return 0;
}

static int xmp_fsync(const char *path, int isdatasync)
{
    /* Just a stub.  This method is optional and can safely be left
       unimplemented */
char fpath[1000];
    sprintf(fpath,"%s%s",dirpath,path);
    (void) fpath;
    (void) isdatasync;
    return 0;
}

static struct fuse_operations xmp_oper = {
    .getattr    = xmp_getattr,
    .readlink    = xmp_readlink,
    .getdir    = xmp_getdir,
    .mknod    = xmp_mknod,
    .mkdir    = xmp_mkdir,
    .symlink    = xmp_symlink,
    .unlink    = xmp_unlink,
    .rmdir    = xmp_rmdir,
    .rename    = xmp_rename,
    .link    = xmp_link,
    .chmod    = xmp_chmod,
    .chown    = xmp_chown,
    .truncate    = xmp_truncate,
    .utime    = xmp_utime,
    .open    = xmp_open,
    .read    = xmp_read,
    .write    = xmp_write,
    //.statfs    = xmp_statfs,
    .release    = xmp_release,
    .fsync    = xmp_fsync
   
};

int main(int argc, char *argv[])
{
    fuse_main(argc, argv, &xmp_oper);
    return 0;
}

Bisa dilihat dikodingan diatas yang dimodify adalah fungsi write dan fungsi read, dimana saat kita mengcopy sebuah file, pastiya file yang akan dicopy akan di read terlebih dahulu, sehingga saat di read, kita menyimpan file pathnya (dengan menggunakan strcpy).

Kemudian saat di write, kita akan melakukan chmod untuk melakukan lock pada file source tersebut.

Setelah koding diatas selesai, simpan dalam bentuk .c . kemudian kalian bisa mengcompile .c tersebut dengan cara:
gcc -Wall [nama file].c `pkg-config fuse --cflags --libs` -o [nama file]
 setelah berhasil di compile kita dapat run file kita dengan cara:
./file /tmp/fuse

Diatas menunjukan bahwa kita akan melakukan mount pada folder /tmp/fuse .
Anda harus memastikan bahwa folder yang anda gunakan untuk mount adalah folder kosong.

Silakan mencoba hehe.

Saturday, 7 November 2015

Shared Memory

Jadi waktu itu gw ditanyain gitu, shared memory apa sih ? Cara kerjanya gimana sih? itu kenapa simple sih daripada piping?

well, basically dengan shared memory , kita dapat mengalokasikan suatu memory yang bisa digunakan antar process, jadi bisa membuat suatu Interprocess Communication. Walaupun ada cara IPC lain, tapi menurut saya shared memory lebih simple untuk dicoding. Karena, berbeda dengan misalnya piping dimana anda harus menentukan kapan setiap process harus read dan write, dengan shared memory, kamu bisa mengupdate variable yang di share secara otomatis.

CARA MEMBUAT SHARED MEMORY:

The Gist of it
1. Menentukan key
2. Membuat Shared Memory ID
3. Mendapatkan address dari shared memory

WAT? THAT SIMPLE? yeap yeap, bisa lah ya.

1.  Menentukan key
Jadi, key itu digunakan buat mendapatkan shared memory id. Kenapa kita perlu id? Karena bisa saja dalam satu process ada lebih dari 1 shared memory, jadi untuk membedakan shared memory satu dan yang lain. Key yang digunakan bisa bebas, intinya , key yang di set di satu process harus sama dengan key yang di process lain.
    key_t key;
   key = 1111;
Bisa dilihat diatas, saya melakukan set key menjadi 1111, key disini bebas bisa 1234 bisa 00000 atau yang lain asalkan key di process lain sama (tentunya pada shared memory yang sama).
Pembuatan key bisa juga menggunakan ftok()/
 key_t ftok(const char *path, int id);

2.Membuat Shared Memory ID
Dengan key yang telah dibuat kita bisa mendapatkan shared memory id dengan fungsi shmget.
shmid =  shmget(key,sizeof(struct barang), IPC_CREAT | 0666);
code diatas menunjukan bahwa saya akan menyimpan shared memory id ke shmid. Disitu ada IPC_CREAT |0666 dimana dia akan membuat interprocess communication yang memiliki premission untuk melakukan read dan juga write.

3.Mendapatkan address dari shared memory
Setelah mendapatkan ID, kita bisa langsung mendapatkan address dari shared memory tersebut.
 shmat(shmid,NULL,0);
Setelah menyimpan address kedalam suatu variable, kita dapat langsung mengubah variable  dan akan secara otomatis berpengaruh ke process lain yang memiliki akses ke shared memory.

Contoh:

Disini saya akan memberikan contoh dari penggunaan shared memory :
Contohnya yaitu IPC antara process pemilik toko dan process client. pemilik memiliki menu untuk menambahkan stok dan lihat stok. sedangkan pembeli atau client memiliki menu untuk membeli barang dan lihat stok.

Server:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

struct barang{
    char name[6][20];
    int jumlah[6];
};

int main (int argc , char **argv)
{
    struct barang *barangs;
    int banyak;
    char stockname[20];
    int shmid, pilihan;
    key_t key;
    int i;
    key = 1111;
    shmid =  shmget(key,sizeof(struct barang), IPC_CREAT | 0666);
    barangs =(struct barang *) shmat(shmid,NULL,0);
    for(i=0;i<6;i++)
    {
        if(i==0) strcpy(barangs->name[i],"RAM");
        else if(i==1) strcpy(barangs->name[i], "harddisk");
        else if(i==2) strcpy(barangs->name[i], "motherboard");
        else if(i==3) strcpy(barangs->name[i], "PSU");
        else if(i==4) strcpy(barangs->name[i], "VGA");
        else if(i==5) strcpy(barangs->name[i], "processor");
        barangs->jumlah[i] = 0;
    }
    int flag;
    while(1)
    {
        printf("######SELAMAT DATANG DI TOKO OINK######\n");
        printf("##                     ##\n");
        printf("##1.Lihat stok         2.Tambah Stok##\n");
        printf("##                     ##\n");
        printf("#######################################\n");
        scanf("%d",&pilihan);
       
        if( pilihan == 1)
        {
            system("clear");
            printf("NAMA BARANG\tJUMLAHBARANG\n");
            for(i=0;i<6;i++)
            {
                if (i==0 || i== 3 || i== 4)
                {
                    printf("%s\t\t%d\n", barangs->name[i], barangs->jumlah[i]);
                }
                else printf("%s\t%d\n", barangs->name[i], barangs->jumlah[i]);
            }
        }
        else if( pilihan == 2)
        {
            flag =0;
            printf("Masukkan nama barang yang ingin ditambah stoknya > ");
            scanf("%s",stockname);
            printf("Masukkan jumlah penambahan > ");
            scanf("%d", &banyak);

            system("clear");
            for(i=0;i<6;i++)
            {
                if (strcmp(stockname, barangs->name[i]) == 0)
                {
                    flag =1;
                    barangs->jumlah[i] += banyak;
                    printf("Anda telah menambah stok barang %s sebanyak %d\n", barangs->name[i], banyak);
                    sleep(3);
                    system("clear");

                }
               
            }
            if (flag == 0) system("zenity --warning --text='INPUT INVALID'");
        }
        else {
            system("clear");
            system("zenity --warning --text='INPUT INVALID'");
            }
    }
}
Client , hmm , jadi gimana ya kalo kita di process client ada menu beli barang dan lihat stok?
Kurang lebih sama, bedanya, anda tak perlu melakukan inisialisasi, karena inisialisasi sudah dilakukan di server dan anda sudah bisa mengakses di process pembeli, karena sudah terupdate. bedanya lagi terletak dimana saat pemilik menambahkan stok, sudah pasti stok bertambah, tetapi jika client membeli stok, stok berkurang, perlu juga dibuat error handling  seperti apabila stok yang ingin dibeli oleh client tidak cukup dengan jumlah yang ada di gudang.

Gimana? gampang kan? bisa dehh, silakan mencoba ya...

Saturday, 17 October 2015

DARIPADA NGELAMUN MENDING BUAT DAEMON YUK COY AHELAH

Dah tau kan Daemon itu apa?
Kalo belom: https://en.wikipedia.org/wiki/Daemon_(computing)
Disini saya cuma bakal jelasin cara membuat daemon di linux. Easy lah. :^)


THE GIST OF IT :
1. Melakukan proses Forking
2. Mengganti File Mode menjadi mask
3. Membuat Unique Session ID
4. Mengganti working directory
5. Menutup Standard File Descriptor (STDIN, STDOUT, STDERR)
6. Memasukan Code tujuan pembuatan Daemon


EXPLANATION:

Jangan lupa sebelum memasukan code dibawah ini untuk memanggil library yang digunakan

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <unistd.h>
    #include <syslog.h>
    #include <string.h>


1. Melakukan proses Forking.


 Daemon bisa dijalankan oleh system maupun user sendiri melalui terminal atau melalui script. Saat mulai dijalankan, processnya seperti executable pada system. Caranya adalah dengan melakukan forking.

    pid_t pid;

            /* Fork off the parent process */       
            pid = fork();
            if (pid < 0) {
                    exit(EXIT_FAILURE);
            }

            /* If we got a good PID, then
               we can exit the parent process. */

            if (pid > 0) {
                    exit(EXIT_SUCCESS);
            }


Fungsi Fork() diatas mengembalikan sebuah value, dimana jika fungsi Fork gagal dalam melakukan tugasnya, ia akan mengembalikan nilai -1 dan daemon berhenti saat itu juga. Namun, jika fungsi Fork berhasil, ia akan mengembalikan nilai PID dari children process.

2. Mengganti Filemode menjadi Mask


Untuk melakukan write file oleh daemon (misal pembuatan log) , maka harus dilakukan penggantian file mode menjadi mask agar file yang dibuat bisa dibaca dan di-write secara benar.

    umask(0);

 3. Membuat Unique Session ID

 Agar child process hasil fork tadi dapat beroperasi, dibutuhkan untuk membuat Unique Session ID

    pid_t sid;

    /* Create a new SID for the child process */
            sid = setsid();
            if (sid < 0) {

                    /* Log any failure */
                    exit(EXIT_FAILURE);
            }


Tipikal return valuenya kayak pas forking gitu.

4. Mengganti working directory

Karena kita mau menggunakan directory yang selalu ada maka kita bisa menggunakan root (/) bisa juga sih directory yang lain.

    if ((chdir("/")) < 0) {
                    /* Log any failure here */
                    exit(EXIT_FAILURE);
            }


Return value masih kayak biasa

5. Menutup Standard File Descriptor (STDIN, STDOUT, STDERR)
Biasanya daemon tidak menggunakan terminal, jika anda tidak ingin daemon untuk menggunakan terminal gunakan code dibawah ini:

       close(STDIN_FILENO);
     close(STDOUT_FILENO);
     close(STDERR_FILENO);
6. Memasukan Code tujuan pembuatan Daemon

 Nah kita tau kalo daemon itu processnya terus menerus mengulang kan? Nah untuk itu kita menggunakan loop while(1) untuk melaksanakan process inti dari daemon.

Here's the thing, Seperti yang kita tau seluruh program kita akan di save dalam .c dimana ("menurut gw") menggunakan C buat akses file, directory, move directory is a PAIN. Jadi bisa aja kalian buat 1 file pihak ketiga dengan bash yang dijalankan oleh system seperti dibawah ini.

    while(1){
               system("./test.sh");
               sleep(30); /* wait 30 seconds */
            }


Contoh diatas itu menunjukan kalo kita ingin melakukan run terhadap file test.sh yang dicode menggunakan bash. Sure, cara ini memang terkesan agak malas. Tapi ya, itu hanya tips agar programming lebih simple aja (at least menurut saya). But still, jika anda ingin menggunakan C secara utuh juga bisa. OR..... mix a little bit of both?

    while(1) {  
               system("mv test.txt testnew.txt");
               sleep(30); /* wait 30 seconds */
            }


Code diatas digunakan untuk melakukan rename test.txt menjadi testnew.txt. Di code ini kalian tidak perlu membuat file .sh satu lagi, but in the same time, anda juga menggunakan bash (which is a lot easier in this case). Namun cara ini memiliki flaw, seperti misalnya anda hanya bisa memasukan fungsi fungsi yang biasa diakses di terminal. Jika kalian mau menulis code panjang dengan pengulangan percabangan dll. Yang pastiya tida bisa dengan melakukan cara diatas. Better stick with that third party file or C :^)


Setelah filenya kamu simpan di C
Lakukan code ini untuk membuat file daemonnya di terminal
gcc -o daemon.o test.c


Kalian akan membuat daemon.o dari file test.c , setelah terbuat file .o run file lewat terminal dengan mengetik "./daemon.o"
Jadi ya gitu, pretty easy rite? Cobain daahh. Until Next Time

Saturday, 26 September 2015

Command yang sering digunakan di bash

Biar gak banyak basa basi kayak kebiasaan orang buat ngomong 1 point tapi muterin hutan dulu, kita langsung ke point aja kali ya.

Command yang biasa dipake :

cd
cd memiliki kepanjangan change directory. Obvious sepertinya gunanya untuk apa, ya, buat pindah directory dari satu directory ke directory lain. Dengan command ini kita bisa explore komputer kita dari terminal dengan mudah.

Syntax : 
cd foldername #pindah ke directory yang dituju, kamu bisa memasukan directory name atau bisa juga path dari directory yang dituju.
cd .. #pindah ke directory sebelumnya
cd #kembali ke home
ls
ls digunakan untuk melakukan list file atau directory yang terdapat di directory yang kita tempati contoh penggunaan list:

pwd
pwd digunakan untuk menunjukkan directory path yang kita tempati sekarang
contoh :



mkdir:
mkdir digunakan untuk membuat folder baru

Syntax:
mkdir directoryname #dengan ini kita membuat folder baru dan menamakan dengan nama yang kita mau
mkdir $variablename #dengan ini kita membuat folder baru dan menamakan sesuai dengan yang disimpan dalam suatu variable
rm
rm digunakan untuk menghapus file yang ada atau jika ingin melakukan penghapusan directory, bisa menggunakan rmdir

Syntax:
rm filename #menghapus file
rmdir directoryname #menghapus suatu directory
mv
mv digunakan untuk memindahkan suatu file ke directory lain, atau bisa juga digunakan untuk merename suatu file

Syntax:
mv note.txt /home/usr/bimo/ #memindahkan note.txt ke directory /home/usr/bimo/
mv note.txt note.c #melakukan rename file dari note.txt jadi note.c
nano:
nano digunakan untuk membuat suatu file baru dengan text editor

Syntax:
nano filename.sh #membuat file baru bernama filename berextensi .sh
wget:
wget digunakan untuk mendownload file atau mengambil file dari internet

Syntax:
wget "http://testdownload.com/download/test.txt" #mendownload file dari alamat sebuah website
wget -O "contoh.txt" "http://testdownload.com/download/test.txt" #dengan -O kita dapat melakukan rename file atau menyimpan ke folder tertentu dari hasil download kita
chmod:
chmod digunakan untuk mengganti permission untuk mengakses mengedit dll untuk sebuah file

Syntax:
chmod 777 filename #memberikan akses penuh ke user , admin dan group 
tar:
tar digunakan untuk melakukan compress terhadap sebuah folder

Syntax:
tar -cvzf B07.tar.gz $tanggal
#bingung gak sih? ya gw juga awalnya, penjelasan yang gw tulis gini
#tar [permission] [nama archive] [file atau folder yang ingin di archive]

sed:
sed bisa digunakan untuk menghapus pada file atau bisa juga melakukan substitute.

Syntax:  
sed -i "1,5d' filename.txt #menghapus baris 1 sampai 5 di file bernama filename.txt
sed 's/^0*// #melakukan substitute terhadap angka 0 dengan null sehingga menghapus setiap bertemu angka 0

Jadi diatas itu adalah command-command yang biasa dimasukan di terminal (bisa juga untuk file .sh). Sekarang saya akan memberikan contoh-contoh syntax dalam membuat file .sh 

Untuk melakukan printing:
melakukan printing bisa menggunakan echo
jadi syntaxnya seperti ini
echo "halo cuy" #hal ini akan menampilkan kalimat "halo cuy" di terminal
kita juga bisa melakukan printing kedalam file jadi
echo "halo cuy" >> file.txt #dengan ini kita bisa melakukan print "halo cuy" ke dalam file.txt

Untuk melakukan percabangan:
melakukan percabangan masih mirip seperti syntax pada bahasa yang lain misalnya : 
if [ $i -eq $j ] #jika value i sama dengan value j
then
#do something
fi #menutup percabangan
di bash kita  mengenal persyaratan dalam percabangan menjadi:
-eq sama dengan
-ne tidak sama dengan
-lt lebih kecil
-gt lebih besar
-le lebih kecil sama dengan
-ge lebih besar sama dengan

Untuk melakukan perulangan:
melakukan perulangan juga mirip seperti syntax dibahasa lainnya misalnya:

for i in `seq 2 $data`; #increment mulai dari 2 sampai value variable data
do #buka loop

#code inside
done #tutup loop

bisa juga menggunakan while
while read line #melakukan loop sampai file line akhir
do
#some stuff
done < "$var" #berdasarkan filename bernama isi dari variable var

Contoh program mencari bilangan prima sebelum input:

Jika dijalankan :

itu aja untuk minggu ini, jangan lupa untuk file path folder dll itu adalah case sensitive, jadi make sure yang kamu masukan itu sesuai casenya dengan yang ada. Sama halnya dengan commands-nya, itu juga case sensitive.

Silakan mencoba!