Skip to content

Conversation

@rahuld109
Copy link

@rahuld109 rahuld109 commented Dec 19, 2025

Hey! I noticed issue #951 had been open for a while and figured I'd take a crack at it. Added a bunch of stdlib functions that were requested:

What's included:

  • uname_* functions (kernel name, nodename, release, version, machine, os, all) - basically wrapping the uname command
  • lines_count, words_count, chars_count - text counting utilities using wc
  • sort_lines, sort_lines_desc, sort_lines_numeric - sorting helpers
  • uniq_lines, uniq_all_lines - deduplication (adjacent vs all duplicates)
  • mount, umount, umount_force - filesystem mounting (with sudo modifier)
  • pgrep, pgrep_exact, pkill, pkill_exact, pkill_force - process management

Added tests for everything too. The pgrep tests are in the no_output directory since the results depend on what's running.

Closes #951
Partial fix for #954

…nctions

Added new stdlib functions:

env.ab:
- uname_kernel_name() - returns kernel name (e.g., Linux, Darwin)
- uname_nodename() - returns network hostname
- uname_kernel_release() - returns kernel release version
- uname_kernel_version() - returns kernel version
- uname_machine() - returns machine architecture
- uname_os() - returns OS name
- uname_all() - returns all uname info
- mount() - mounts a filesystem (requires root)
- umount() - unmounts a filesystem (requires root)
- umount_force() - force unmounts a filesystem
- pgrep() - finds process IDs by name pattern
- pgrep_exact() - finds process IDs by exact name
- pkill() - kills processes by name pattern
- pkill_exact() - kills processes by exact name
- pkill_force() - forcefully kills processes (SIGKILL)

text.ab:
- lines_count() - counts lines in text
- words_count() - counts words in text
- chars_count() - counts characters in text
- sort_lines() - sorts lines alphabetically
- sort_lines_desc() - sorts lines in descending order
- sort_lines_numeric() - sorts lines numerically
- uniq_lines() - removes consecutive duplicate lines
- uniq_all_lines() - removes all duplicate lines

Closes amber-lang#951
@Tirito6626
Copy link
Member

pretty good, but usage examples should be updated (see #954)

@Tirito6626
Copy link
Member

you could also make use of sudo modifier for functions that require root permsisions

@Mte90
Copy link
Member

Mte90 commented Dec 19, 2025

Cool!

The commands that require sudo are mount/umount. I will review the code asap!

- Changed echo to echo() in usage examples (v0.6.0+ syntax)
- Added sudo modifier to mount/umount functions for privilege escalation
@Mte90 Mte90 requested review from Mte90 and Tirito6626 December 19, 2025 08:18
@rahuld109
Copy link
Author

Thanks for the feedback! I've updated the PR:

  • Changed all echo to echo() in usage examples (v0.6.0+ syntax)
  • Added sudo modifier to mount(), umount(), and umount_force() for intelligent privilege escalation

@Tirito6626
Copy link
Member

code seems fine but i will also test it locally later

Copy link
Member

@Mte90 Mte90 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some changes needed but tests works with no errors

src/std/env.ab Outdated
#[allow_absurd_cast]
pub fun pgrep(pattern: Text): [Int] {
let result = [Int]
trust $ while read -r pid; do {nameof result}+=("\$pid"); done < <(pgrep "{pattern}" 2>/dev/null) $
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This while needs to be in amber code

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done - rewrote it using split_lines() and parse_int() instead

/// pkill("nginx")?
/// ```
pub fun pkill(pattern: Text): Null? {
$ pkill "{pattern}" $?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return pkill output can be helpful?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think it would be also useful to be able to use PIDs and signal to send (e.g. SIGTERM or SIGINT, etc). kill could be used as fallback, since it's a bash builtin

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kept it as Null? for now since pkill doesn't output much useful info. Let me know if you'd prefer something different

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea - added a kill(pid, signal) function that defaults to TERM. Works with signal names or numbers

@rahuld109
Copy link
Author

Hey, thanks for the feedback! I've made the changes:

  • Rewrote the bash while loops in pgrep/pgrep_exact to use native Amber - now using split_lines() and parse_int() instead

  • Added a kill() function that takes a PID and optional signal (defaults to TERM). Should cover the use cases you mentioned:

    kill(1234)?              // SIGTERM
    kill(1234, "SIGKILL")?   // or "9" works too
    

Let me know if there's anything else!

- Convert bash while loops to native Amber code in pgrep/pgrep_exact
- Add kill() function with PID and signal support (SIGTERM, SIGKILL, etc.)
- Use split_lines() and parse_int() for cleaner implementation
@rahuld109 rahuld109 force-pushed the feat/stdlib-functions branch from 162952e to b4bc86d Compare December 19, 2025 17:49
@Tirito6626
Copy link
Member

why always using nameof instead of parsing the value directly?

@Tirito6626 Tirito6626 requested a review from Mte90 December 19, 2025 19:12
@rahuld109
Copy link
Author

This is already fixed in the latest commit - I removed the nameof/while loop and now it uses native Amber:

let output = trust $ pgrep "{pattern}" 2>/dev/null $
let lines = split_lines(output)
for line in lines {
    let pid = parse_int(line) failed { continue }
    result += [pid]
}

You might be seeing a cached diff - try refreshing the page

@Tirito6626
Copy link
Member

i would also consider using here-string instead of printf pipe where possible, but i could do that after the merge, since i'd have to rework files anyways

- Simplified sort_lines, sort_lines_desc, sort_lines_numeric
- Simplified uniq_lines, uniq_all_lines
- Simplified lines_count, words_count
- Keep printf for chars_count (here-string adds newline)
@rahuld109
Copy link
Author

Applied the here-string suggestions - thanks for the cleaner approach!

  • sort_lines, sort_lines_desc, sort_lines_numeric
  • uniq_lines, uniq_all_lines
  • lines_count, words_count

Kept chars_count using printf since here-string adds a trailing newline which breaks the character count.

Copy link
Member

@Tirito6626 Tirito6626 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks way better now, time to run tests

Copy link
Member

@Ph0enixKM Ph0enixKM left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job @rahuld109 ! Thank you for your contribution. This is a very well-written Amber code! Here are some minor suggestions regarding the library functions structure as a whole.

///
/// ### Usage
/// ```ab
/// mount("/dev/sda1", "/mnt/disk")?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to add usage example for mount with options?

Comment on lines +510 to +519
/// ### Usage
/// ```ab
/// let count = lines_count("one\ntwo\nthree")
/// echo(count) // 3
/// ```
#[allow_absurd_cast]
pub fun lines_count(text: Text): Int {
if text == "": return 0
return trust $ wc -l <<< "{text}" | tr -d ' ' $ as Int
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that count_lines sounds better

Suggested change
/// ### Usage
/// ```ab
/// let count = lines_count("one\ntwo\nthree")
/// echo(count) // 3
/// ```
#[allow_absurd_cast]
pub fun lines_count(text: Text): Int {
if text == "": return 0
return trust $ wc -l <<< "{text}" | tr -d ' ' $ as Int
}
/// ### Usage
/// ```ab
/// let count = count_lines("one\ntwo\nthree")
/// echo(count) // 3
/// ```
#[allow_absurd_cast]
pub fun count_lines(text: Text): Int {
if text == "": return 0
return trust $ wc -l <<< "{text}" | tr -d ' ' $ as Int
}

Comment on lines +524 to +531
/// ```ab
/// let count = words_count("hello world foo")
/// echo(count) // 3
/// ```
#[allow_absurd_cast]
pub fun words_count(text: Text): Int {
return trust $ wc -w <<< "{text}" | tr -d ' ' $ as Int
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that count_words sounds better

Suggested change
/// ```ab
/// let count = words_count("hello world foo")
/// echo(count) // 3
/// ```
#[allow_absurd_cast]
pub fun words_count(text: Text): Int {
return trust $ wc -w <<< "{text}" | tr -d ' ' $ as Int
}
/// ```ab
/// let count = count_words("hello world foo")
/// echo(count) // 3
/// ```
#[allow_absurd_cast]
pub fun count_words(text: Text): Int {
return trust $ wc -w <<< "{text}" | tr -d ' ' $ as Int
}

Comment on lines +533 to +543
/// Counts the number of characters in the given text.
///
/// ### Usage
/// ```ab
/// let count = chars_count("hello")
/// echo(count) // 5
/// ```
#[allow_absurd_cast]
pub fun chars_count(text: Text): Int {
return trust $ printf "%s" "{text}" | wc -m | tr -d ' ' $ as Int
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like count_chars sounds better

Suggested change
/// Counts the number of characters in the given text.
///
/// ### Usage
/// ```ab
/// let count = chars_count("hello")
/// echo(count) // 5
/// ```
#[allow_absurd_cast]
pub fun chars_count(text: Text): Int {
return trust $ printf "%s" "{text}" | wc -m | tr -d ' ' $ as Int
}
/// Counts the number of characters in the given text.
///
/// ### Usage
/// ```ab
/// let count = count_chars("hello")
/// echo(count) // 5
/// ```
#[allow_absurd_cast]
pub fun count_chars(text: Text): Int {
return trust $ printf "%s" "{text}" | wc -m | tr -d ' ' $ as Int
}

Comment on lines +545 to +576
/// Sorts lines of text in ascending order.
///
/// ### Usage
/// ```ab
/// let sorted = sort_lines("banana\napple\ncherry")
/// echo(sorted) // "apple\nbanana\ncherry"
/// ```
pub fun sort_lines(text: Text): Text {
return trust $ sort <<< "{text}" $
}

/// Sorts lines of text in descending order.
///
/// ### Usage
/// ```ab
/// let sorted = sort_lines_desc("banana\napple\ncherry")
/// echo(sorted) // "cherry\nbanana\napple"
/// ```
pub fun sort_lines_desc(text: Text): Text {
return trust $ sort -r <<< "{text}" $
}

/// Sorts lines of text numerically.
///
/// ### Usage
/// ```ab
/// let sorted = sort_lines_numeric("10\n2\n1")
/// echo(sorted) // "1\n2\n10"
/// ```
pub fun sort_lines_numeric(text: Text): Text {
return trust $ sort -n <<< "{text}" $
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's combine these functions into one function:

pub fun sort_lines(text: Text, desc: Bool = false, numeric: Bool = false)

Comment on lines +578 to +598
/// Removes consecutive duplicate lines from text.
///
/// ### Usage
/// ```ab
/// let result = uniq_lines("foo\nfoo\nbar\nbar\nbaz")
/// echo(result) // "foo\nbar\nbaz"
/// ```
pub fun uniq_lines(text: Text): Text {
return trust $ uniq <<< "{text}" $
}

/// Removes all duplicate lines from text (not just consecutive).
///
/// ### Usage
/// ```ab
/// let result = uniq_all_lines("foo\nbar\nfoo\nbaz\nbar")
/// echo(result) // "foo\nbar\nbaz"
/// ```
pub fun uniq_all_lines(text: Text): Text {
return trust $ awk '!seen[\$0]++' <<< "{text}" $
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like the following names make more sense to me:

  • uniq_lines_adj- this only removes adjacent duplicates
  • uniq_lines - this removes global duplicates

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] New stdlib functions

4 participants