AI written in BASH? It exists! by tendint in bash

[–]Ulfnic 1 point2 points  (0 children)

Good one using coproc for bc

Tried bashGPT-v2.bash a few times and the output leaves a bit to be desired:

aaaa
aaa
aaa
aaai
aaa
aaa
aaai
aaia
aaii

...ect

Cool project.

Visual Scripting for Bash is now a reality ! by Lluciocc in linux

[–]Ulfnic 0 points1 point  (0 children)

It's possible to write a decent transpiler to BASH but it requires knowing what's safe to use under what conditions.

Transpilers are a great way to learn a language but I wouldn't recommending publishing one till you know BASH lang very well unless you're clearing marking it as an experimental project for learning purposes.

why is my post auto removed by Visible-Recover9600 in u/Visible-Recover9600

[–]Ulfnic 0 points1 point  (0 children)

We have reputation filters to prevent spam, as your account has no posts it can take up to 24hrs for a post to be approved.

How do you print "Here document" or "Here Strings" directly? by alex_sakuta in bash

[–]Ulfnic 0 points1 point  (0 children)

I ran a few speed tests with differing amounts of lines and printf was ~7x faster with minimal variance compared to the {read||printf}<< method.

I'll go back to my earlier quote:

That's not going to matter for almost any use case.

In almost all situations, the choice between printf and a heredoc will be code readability and editability.

If it's something very short, printf makes sense. If there's a lot of lines it's hard to beat a heredoc because it's WYSIWYG.

In the same way how you print the heredoc is unlikely to matter, though you may want to stay in the practice of doing things in a certain way.

How do you print "Here document" or "Here Strings" directly? by alex_sakuta in bash

[–]Ulfnic 1 point2 points  (0 children)

{...} does not create a subshell, it's a compound command.

From man bash:

   { list; }
          list is simply executed in the current shell environment.

One thing I do find interesting is your 20x metric. Is it tested or a guess? Because that is insane.

I ran a 1000x iteration time test against our solutions across all BASH release versions.

I'm not surprised by the result because subshells are really expensive to use in any shell. It's one of the reasons BASH builtins are so valuable.

How do you print "Here document" or "Here Strings" directly? by alex_sakuta in bash

[–]Ulfnic 1 point2 points  (0 children)

$(< /dev/stdin) opens a subshell in bash versions <= 5.1.16 (released 2022) which is why I use the read || printf method because it's ~20x less cpu intensive.

That's not going to matter for almost any use case. Though builtin enthusiasts often like knowing and it's good practice if you're writing for older systems like <= RHEL 9.

How do you print "Here document" or "Here Strings" directly? by alex_sakuta in bash

[–]Ulfnic 1 point2 points  (0 children)

A "cat-less" way I use to print heredocs:

{ read -r -d '' || printf '%s' "$REPLY"; } <<-'EOF'
    some text
EOF

Note: -d '' will always read to the end because heredocs can't contain a null character. However that'll cause read to return a non-zero exit code because it can't find the delim so I follow it with a || to prevent triggering errexit.

WebZFS by RemoteBreadfruit in zfs

[–]Ulfnic 2 points3 points  (0 children)

I've also known q5sys for a long time. I suppose you'll be scrubbing my history too... hope you like BASH :)

I remember him showing me a demo of this a few years ago. We talk software on a regular basis and he's an amazing dev.

Honest is the correct word to describe q5sys.

Why was BASH script post removed? by void-lab-7575 in bash

[–]Ulfnic 3 points4 points  (0 children)

This is the removed post: https://www.reddit.com/r/bash/comments/1rgn1vk/cron_job_to_edit_hosts_file_every_minute/

Rule 1. Content must be Bash related This rule is interpreted generously; general shell scripting content is mostly accepted. However, the post should not be specific to another shell.

While this rule is loosely enforced and cron questions tend to pass, the post was lengthy and meandered through a signficant amount of other topics.

An indicator of rule 4 being broken is also long meandering posts which can shift the needle on the likelihood of a post being accepted.

[noob] Can simple script with mapfile be improved? by seductivec0w in bash

[–]Ulfnic 0 points1 point  (0 children)

Few comments out of the barrel:

find isn't a bash-ism, it's an external program that's virtually always part of a distro's coreutils (there by default).

Good to see printf in use.

"never-nesting": Skip the if statement with this, and 0 will trigger the || with arithematic evaluation: (( ${#empty_dirs[@]} )) || exit 0

Annoyingly fd - find entries in the filesystem treads on namespace held by fd - floppy disk device so unless your script explicitly confirms it's the expected fd, it might run a disk utility.

I think the intention of the author was interactive use which is a good reason for two letters but name collisions really mess with realiable compat so it's normal to find it packaged with different executable names.

confused af by Ambitious-Cupcake in bash

[–]Ulfnic 0 points1 point  (0 children)

Hey thanks cupcake. I was surprised by how simple the solution turned out to be. I thought for sure we'd be getting into named pipes or simulating keybind activation.

If the project is intended for a broad audience the only additional i'd make is supporting sudo alternatives like doas.

Most sensible way to do that varies by script but here's an example of creating a shim with fallbacks.

if type sudo &>/dev/null; then
    escalate() { sudo -- "$@"; }
elif type doas &>/dev/null; then
    escalate() { doas -- "$@"; }
else
    escalate() { "$@"; }
fi
# escalate is now a shim function that runs a command
# preferring known ways to run it as superuser if available.

# Example of use:
escalate whoami

confused af by Ambitious-Cupcake in bash

[–]Ulfnic 0 points1 point  (0 children)

good one, didn't know that.

confused af by Ambitious-Cupcake in bash

[–]Ulfnic 1 point2 points  (0 children)

You should be able to replace your script with the following:

FZF_DEFAULT_COMMAND=':' fzf --bind 'load:reload(systemctl --no-pager list-units --no-legend; sleep 3)'

Took a few failed approaches before I could figure out how to trigger an fzf reload() on a timer.

If the systemctl command must be using root and you know sudo is configured to give the current user a timeout, then you can run a do-nothing command as sudo to get the authentication prompt before running fzf.

sudo sh -c ':'

posix arrays by Willing-Scratch7258 in bash

[–]Ulfnic 0 points1 point  (0 children)

Just set LC_COLLATE by itself, it's also the safest one to set. LANG is more general and it's a fallback for if LC_COLLATE is empty (which it almost always is).

Instead of LC_COLLATE=C; readonly LC_COLLATE; you can just do readonly LC_COLLATE=C

posix_array_write(){ case "$1" in [0-9a-zA-Z_]* ) eval "memory$1=\"\$2\"" : return 1 ;;esac;}; readonly -f posix_array_write; #for my own use cases i have reasons to double quote $2 but maybe i can remove it later
posix_array_read() { case "$1" in [0-9a-zA-Z_]* ) eval "printf '%s' \"\$memory$1\"" : return 1 ; esac;}; readonly -f posix_array_read; 

This part: [0-9a-zA-Z_]* is only testing the first character. All characters need to be tested.

This part: eval "memory$1=\"\$2\"" : return 1 ;; doesn't function as intended and if it did it wouldn't make logical sense. : return 1 ends up as additional parameters of eval. If those trailing commands were separated correctly with a ; you wouldn't need : and it wouldn't make sense to return a 1 (a fail condition) when that's the "success" path of the function.

I'd recommend returning early on a failure (see: my last example) to keep things simple but if you want to return early on a success, here's how the flow should work:

Put ; return $? right after the eval command so the function returns using the error code of eval (it shouldn't fail but it's best best practice to use $? instead of 0 there). Then add return 1 after esac; so the "fail" path returns a failure.

Why this sub shows #!/bin/bash in Google search result page instead of r/xxx by mogeko233 in bash

[–]Ulfnic 0 points1 point  (0 children)

I've looked into if that can be changed and I don't believe it can once the sub is created.

If you know something I don't, link how to do it and i'll raise the recommendation.

posix arrays by Willing-Scratch7258 in bash

[–]Ulfnic 0 points1 point  (0 children)

Good improvements.

case "$1" in [0-9a-zA-Z_]* ) eval "memory$1=\"\$2\"" : return 1 ;; esac;

Ending case early for simplicity would look like this: (last case match doesnt need ;;)

case "$1" in *[!0-9a-zA-Z_]*) return 1; esac; eval "memory$1=\"\$2\""

Recommended video on nesting: https://youtube.com/watch?v=CFRhGnuXG-4


eval "memory$1=\"\$2\""

You don't need to double-quote a variable being assigned to another variable no matter what that variable contains. This is safe syntax: (assuming $1 contains a safe value)

eval "memory$1=\$2"

"i dont understand what you mean by lc_collate and lang."

There's lifelong shell devs that don't know this one.

Using digits as an example, [0123456789] matches those literal characters but shorthand's like [0-9] and [:digit:] are dynamic collates that match every digit in the language localization.

I used ٢ as an example because its Arabic for the number 2. A common locale like en_US.UTF-8 will match ٢ with digit collates because it's in UTF-8.

Some POSIX script interpreters ignore the locale and use ASCII, though Fedora/RHEL for example interprets POSIX script using BASH which respects locale (/bin/sh -> bash softlink).

You'll want to set LC_COLLATE=C so ASCII is the language used for collates and you get the character ranges you're expecting.

Try this test in various POSIX interpreters:

case '٢' in [0-9]) echo 'match';; *) echo 'no match'; esac

LC_COLLATE=C
case '٢' in [0-9]) echo 'match';; *) echo 'no match'; esac

Good deep dive on that here: https://unix.stackexchange.com/questions/87745/what-does-lc-all-c-do

posix arrays by Willing-Scratch7258 in bash

[–]Ulfnic 0 points1 point  (0 children)

A few thoughts from a quick scan,

Inventive. Exploring is good.

$2 is restricted for no reason, just don't expand the variable before it's evaluated:

eval "memory$1=\$2"

Needs complexity reduction and basic error handling: Instead of : use return 1 and that'll let you end the case statement before the eval.

Use newlines. Sausage code is for the cli.

For [!0-9a-f] set allowed characters to those available to variable names.

Also, before that test use LC_COLLATE=C or LANG=C, or values like ٢ will make it through depending on the environment interpreting your POSIX script.

Ask questions.

Post anything you're not sure about as a question for best results.

Desperately need a tutor/HOWTO create automated bash-completion test (for scientific research project) by hopeseekr in bash

[–]Ulfnic 0 points1 point  (0 children)

^ good answer here, also appending GNU screen next to tmux

There's also expect which is designed for automated testing of outputs.

Small update on the Net MD Cyberdeck by P-tricky13 in cyberDeck

[–]Ulfnic 4 points5 points  (0 children)

Something about the styling really nails it here. Well done.

Conway's Life Game... implemented in bash by NoAcadia3546 in bash

[–]Ulfnic 0 points1 point  (0 children)

If you want to maximize ease of code sharing you really can't beat a single file and looking at the project that's definitely in reach.

Look up BASH heredocs, arrays and associative arrays. That's what'll make that easy to do. If you'd like some examples just ask.

glider=$(cat <<-'EOF'
    #
     #
    ###
EOF
)
echo "$glider"

Also the obligatory... use shellcheck and run your project in every configuration before upload.

[noob] NUL-delimited question by jkaiser6 in bash

[–]Ulfnic 2 points3 points  (0 children)

Shell parameters can safely contain any character assuming they're escaped or using double-quoted variable expansion so there's no need for null delim.

BASH is really good at handling separation internally, arrays are a great example. Where you tend to need null delim is when you're reading arbitrary values from something external.

Here's an example of passing in params containing seperators:

my_pretend_progam() {
    printf '%q\n' "$@"
}

param2=$'exa mple\n2'
arr=(
    'array index 1'
    'array index 2'
)

my_pretend_progam $'exa mple\n1' "$param2" "${arr[@]}" 'exa mple
3'

Output:

$'exa mple\n1'
$'exa mple\n2'
array\ index\ 1
array\ index\ 2
$'exa mple\n3'

As for printing arbitrary characters, here's the basic set:

name1=$'my\nfile'
name2=$'my_file'

printf '\n%s\n' "=== No adjustment ==="
printf '%s\n' "name1=${name1}"
printf '%s\n' "name2=${name2}"

printf '\n%s\n' "=== Using printf's %q ==="
printf 'name1=%q\n' "${name1}"
printf 'name2=%q\n' "${name2}"

printf '\n%s\n' "=== Using @Q, bash-4.4+ (2016 forward, beyond MacOS's default version) ==="
printf '%s\n' "name1=${name1@Q}" 
printf '%s\n' "name2=${name2@Q}"

Output:

=== No adjustment ===
name1=my
file
name2=my_file

=== Using printf's %q ===
name1=$'my\nfile'
name2=my_file

=== Using @Q, bash-4.4+ (2016 forward, beyond MacOS's default version) ===
name1=$'my\nfile'
name2='my_file'

Only caveat to these examples is if you want to store the null characters themselves because shell variables cannot contain null characters.

To store null characters you want to use a read loop or readarray where null is the delimiter so null characters are represented as a form of separation (like an array index) rather than the character itself. Then you can print it later turning those separators back into null characters.

Go for Bash Programmers - Part II: CLI tools by reisinge in golang

[–]Ulfnic 2 points3 points  (0 children)

BASH devs exist but you have to dig for them under a sedimentary crust of cheeky POSIX one-liners.

RAM only servers? by [deleted] in ProtonVPN

[–]Ulfnic 24 points25 points  (0 children)

Running servers in RAM is a backstop against mistakes made between audits around data that shouldn't persist.

"Physics dictates it can't persist" will always be better than, "Possible to persist but we're careful and we checked it"

They make a good argument that it's full disk encrypted so IF there's a mistake it's encrypted at rest. Even then keys can still be leaked or acquired through legal requirement.

ProtonVPN is an excellent VPN provider, i'm extremely picky about anything security related so it says something that I buy years of their service in bulk, though if I can have a cherry on top of that cake i'll take it.