Off-Topic > Off-Topic - Tiny Tux's Corner

[Solved] Asking for recomendations on the shell script formatting.

<< < (3/10) > >>

Rich:
Hi jazzbiker

--- Quote from: jazzbiker on July 19, 2023, 08:43:19 AM --- ... logs are declared as local ... but are used in main(): ...
--- End quote ---
The busybox ash shell includes  local  as one of its built-ins. Enter help in a terminal:

--- Code: ---tc@E310:~$ help
Built-in commands:
------------------
        . : [ [[ alias bg break cd chdir command continue echo eval exec
        exit export false fg getopts hash help history jobs kill let
        local printf pwd read readonly return set shift source test times
        trap true type ulimit umask unalias unset wait
tc@E310:~$
--- End code ---

Here is an example of local:

--- Code: ---#!/bin/sh

Var=5

TestLocal()
{
# This echos the global Var.
echo "2 Var=$Var"

# This overrides the global Var with an empty local Var.
local Var

echo "3 Var=$Var"

# This sets the local Var to 3.
Var=3

echo "4 Var=$Var"
}

echo "1 Var=$Var"
TestLocal
echo "5 Var=$Var"
--- End code ---

This is the result:

--- Code: ---tc@E310:~/split$ ./LocalDemo
1 Var=5
2 Var=5
3 Var=
4 Var=3
5 Var=5
tc@E310:~/split$
--- End code ---

jazzbiker:

--- Quote from: CardealRusso on July 19, 2023, 12:10:09 PM ---Currently, CoreScripts bash scripts are neither easy to read nor user friendly (though understandable).

--- End quote ---

Core scripts have one huge advantage - they work properly ) I don't want to propose repair what's working right. For TinyCore phenomenal stability is absolutely unique. Some features are accessible only in TinyCore.

And even if put the question - what I would like to rewrite in Core? Frankly speaking - nothing. Extending preferably be done in some new ways or new tools, but the Core is wonderful! Stability is easy to destroy but impossible to repair.

If talk about another languages, for example Lua, some things may be taken into consideration. For example I wrote the Lua version of the initial script. Here it is:

--- Code: ---#!/usr/bin/env lua

local TDir, TName = arg[1]:match("(.-)([^/]*)$")

------------------------------------------------
-- Auxillary function to run complex commands --
------------------------------------------------

local run = function(cmd)
  assert(os.execute(table.concat(cmd)))
end

run{"depends-on ", TDir, ".do..", TName}

------------------------------
-- Gathering necessary data --
------------------------------

local jobs = tonumber(os.getenv("JOBS")) or 2

local map_dir = assert(io.popen("cd " .. TDir .. "./; pwd")):read()


-----------------------
-- Storing log names --
-----------------------

local log_names = {}

for i = 1, jobs do
  log_names[#log_names + 1] = string.format("%s.%d.log", arg[1], i)
end


------------------------------------------
-- Creating and running complex command --
------------------------------------------

local cmd = {}

for i, name in ipairs(log_names) do
  cmd[#cmd + 1] = string.format("redo -l %s -m %s %s & ", name, arg[1], arg[2])
end

cmd[#cmd + 1] = "wait"

run(cmd)

----------------------------------------------
-- Concatenation of partial logs in one log --
----------------------------------------------

local log_name = arg[1] .. ".log"

local flog = io.open(log_name, "w")

flog:write("return {\n")

for i, name in ipairs(log_names) do
  flog:write(io.open(name):read("a"))
end

flog:write("}\n")

flog:close()


---------------------------------
-- Loading the processing code --
---------------------------------

log2map = assert(loadfile("log2map.lua"))

------------------------------------
-- Emulating MAP_DIR env variable --
------------------------------------

local getenv_orig = os.getenv

os.getenv = function(name)
  if name == "MAP_DIR" then
    return map_dir
  end
  return getenv_orig(name)
end

------------------------
-- Redirecting stdout --
------------------------

assert(io.output(arg[3]))

-----------------------
-- Processing itself --
-----------------------

log2map(log_name)


--- End code ---

As You can see it is slightly bigger ) Still for me such approach is more comfortable, because everything is clear and all aspects of code are accessible and changeable. No limitations of what can be done - absolutely everything. Which is wrong for shell. Some things are absolutely impossible to do with shell.

GNUser:

--- Quote from: jazzbiker on July 19, 2023, 03:17:43 PM ---Core scripts have one huge advantage - they work properly ) I don't want to propose repair what's working right. For TinyCore phenomenal stability is absolutely unique. Some features are accessible only in TinyCore.

--- End quote ---
Wow, well said! Some TCL scripts are not very pretty but they work perfectly and I wouldn't touch them.

I use my TCL-powered laptop and wireless router daily and my overall impression of TCL is that, by minimizing size and complexity, it is the most stable and easy-to-understand GNU/Linux distribution that exists.

P.S. My *nix journey was Debian -> Arch Linux -> OpenBSD -> Devuan -> TCL. I still manage a Devuan machine in my household (wife's laptop) but I, personally, am 100% TCL. Once you're used to TCL, the complexity and size of other distros is just not acceptable.

jazzbiker:

--- Quote from: Rich on July 19, 2023, 12:54:36 PM ---The busybox ash shell includes  local  as one of its built-ins. Enter help in a terminal:

--- End quote ---

Thanks for explanations and examples, Rich! It works as expected. But in GNUsers example it was looking strange and I was not sure whether it works in shell the same way as in another languages. But GNUser wrote that it is not POSIX feature and for better portability it must not be relied upon.

Best regards!

CardealRusso:

--- Quote from: jazzbiker on July 19, 2023, 03:17:43 PM ---Core scripts have one huge advantage - they work properly

--- End quote ---
I agree. Unfortunately it is sad to see that the latest commits on such scripts go back 10 or more years.

I'm not very familiar with Lua, but it's a surprisingly easy language. Unfortunately, the beginning is interesting but when the lua script ends it is noticeable that its syntax is no longer modern. The constant use of "ends" and other redundancies makes lua outdated.

In case you're curious, I started making a standalone version of tce-size in lua, as a demo. The LOC seems unnecessarily large, but keep in mind that there is no dependency. The script is also incomplete, but is partially working. You can test from https://www.jdoodle.com/execute-lua-online/ and inserting the package name in the argument.


--- Code: ---function GetRemoteContent(url)
    local isGzipped = url:sub(-3) == ".gz"
    local wgetCmd = string.format("wget -q -O- %s", url)
    if isGzipped then
        wgetCmd = string.format("%s | gunzip", wgetCmd)
    end

    local handle = io.popen(wgetCmd)
    local content = handle:read("*a")
    handle:close()

    if content and #content > 0 then
        return content
    else
        print(string.format("Failed to download content from '%s'.", url))
        return nil
    end
end

function getFileSize(sizelistContent, filename)
    for line in sizelistContent:gmatch("[^\r\n]+") do
        local file, size = line:match("(%S+)%s+(%d+)")
        if file == filename then
            return tonumber(size)
        end
    end
    return 0
end

function FileExist(filename)
    local path = "/etc/sysconfig/tcedir/optional/" .. filename
    local file = io.open(path, "r")
    if file then
        file:close()
        return true
    else
        return false
    end
end

local app = arg[1]

if not app then
    print("Specify extension in command line:")
    print("Example:   /usr/bin/tce-size firefox.tcz.")
    return
end

if not app:match("%.tcz$") then
    app = app .. ".tcz"
end

local sizelistURL = "http://tinycorelinux.net/14.x/x86_64/tcz/sizelist.gz"
local treeURL = string.format("http://tinycorelinux.net/14.x/x86_64/tcz/%s.tree", app)

local sizelistContent = GetRemoteContent(sizelistURL)
local treeContent = GetRemoteContent(treeURL)

local totalSizeBytes = 0
local totalSizeNonExistentBytes = 0
local fileList = {}

for filename in treeContent:gmatch("%s*(.-)%s*\n") do
    if filename:sub(-4) == ".tcz" then
        local sizeBytes = getFileSize(sizelistContent, filename)
        totalSizeBytes = totalSizeBytes + sizeBytes
        table.insert(fileList, {filename = filename, sizeBytes = sizeBytes})
    end
end

local function formatSizeMB(sizeBytes)
    return string.format("%.2f MB", sizeBytes / (1024 * 1024))
end

table.sort(fileList, function(a, b) return a.sizeBytes > b.sizeBytes end)

print("  Filename                                 Size (bytes),   Size (MB)")
print("------------------------------------------------------------------")

for _, fileData in ipairs(fileList) do
    local filename = fileData.filename
    local sizeBytes = fileData.sizeBytes

    local fileExists = FileExist(filename)

    if not fileExists then
        filename = "+" .. filename
        totalSizeNonExistentBytes = totalSizeNonExistentBytes + sizeBytes
    end

    print(string.format("  %-40s %12d, %15s", filename, sizeBytes, formatSizeMB(sizeBytes)))
end

print("\n  Total size (bytes)                      " .. string.format("%12d, %15s", totalSizeBytes, formatSizeMB(totalSizeBytes)))
print("  + Indicates need to download            " .. string.format("%12d, %15s", totalSizeNonExistentBytes, formatSizeMB(totalSizeNonExistentBytes)))


--- End code ---

Navigation

[0] Message Index

[#] Next page

[*] Previous page

Go to full version