Gentoo Forums
Gentoo Forums
Gentoo Forums
Quick Search: in
The pain of creating 'universal' shell scripts
View unanswered posts
View posts from last 24 hours

 
Reply to topic    Gentoo Forums Forum Index Gentoo Chat
View previous topic :: View next topic  
Author Message
Zucca
Moderator
Moderator


Joined: 14 Jun 2007
Posts: 3345
Location: Rasi, Finland

PostPosted: Sun Jul 16, 2023 5:24 pm    Post subject: The pain of creating 'universal' shell scripts Reply with quote

TL;DR; - You cannot know which shell interpreter lies at /bin/sh and many common cli tools work differently between publishers/vendors/organizations/developers.

Lately I've been creating scripts that should just work about everywhere. Some may say I'm obsessed with compatibility. One such script is on my phone. Based on the environment it tries to run the script using busybox sh and use as much of its internal commands as possible (to be able to run as fast as possible, although it "won" the speed contest I performed, it did it just barely). If its functions cannot locate busybox, it tries to use as many native (from android system) programs as possible, assuming these were compiled against the specific hardware of the phone.

When I write a POSIXy compliant script, I usually test it with busybox shell as it is little more limited than POSIX sh (afaik) and is pretty common among some minimal and embedded systems.
But then... it isn't still a walk in a park after that. I can pretty safely (foreshadowing...) assume that if I use short options (-v) instead of the gnu long ones (--verbose) the command will run correctly in an environment with coreutils and inside busybox sh.
However! There are differences. In fear of sounding paranoid it feels like some differences were made intentionally. :x
For example I can almost get the same output from busybox ps and coreutils ps by running ps -Ao pid,user,tty,comm ... but not quite. Busybox limits column width. :evil: User 'messagebus. turn into 'messagebu' and many comm columns get shortened too. ARGH! So to get the exact same process output on both ways I guess I need to resort in crawling trough /proc/[0-9]+/. Except that busybox' find uses different regex matching then coreutils' find. Oh great...
So for this particular case I came up with this:
Code:
find /proc -regex '^/proc/[0-9][0-9]*' | while read proc
do
    rp="$(realpath "${proc}/exe" 2> /dev/null)"
    if [ "$rp" != "${proc}/exe" ] && uid="$(cat "${proc}/loginuid" 2> /dev/null)"
    then
        echo "${proc##*/} ${uid} ${rp}"
    fi
done
... and it's pretty slow. Doesn't really matter if you need to run this rarely. But it should produce identical output on both environments.

Do others here feel the same pain?

Sometimes I really think I should just use #!/bin/bash and assume gnu coreutils. *sigh*
_________________
..: Zucca :..
Gentoo IRC channels reside on Libera.Chat.
--
Quote:
I am NaN! I am a man!
Back to top
View user's profile Send private message
Hu
Moderator
Moderator


Joined: 06 Mar 2007
Posts: 21637

PostPosted: Sun Jul 16, 2023 5:48 pm    Post subject: Reply with quote

While GNU may not always make the best decisions, their tools are generally more capable than a pure POSIX system, and those extra features are often useful. I think this is one reason so many people assume GNU tools, rather than coding to pure POSIX.

You might improve your script's performance a bit if you use a built-in read instead of cat for loginuid. Also, prefer cheap tests over expensive ones, so test loginuid before you try to resolve the exe's path. If loginuid fails, you will skip showing the process, and thus skip calling realpath.

Crawling through /proc is inherently racy, so you may get surprising results if a process exits while you are running.
Back to top
View user's profile Send private message
Zucca
Moderator
Moderator


Joined: 14 Jun 2007
Posts: 3345
Location: Rasi, Finland

PostPosted: Sun Jul 16, 2023 6:37 pm    Post subject: Reply with quote

Hu wrote:
Crawling through /proc is inherently racy, so you may get surprising results if a process exits while you are running.
Indeed. I'm trying to avoid recreating the wheel as often as I can.

For this particular case it just seems impossible to get reliably the same output from these different ps -commands.
I guess I need to call it with full path of /bin/ps and call it a day.
_________________
..: Zucca :..
Gentoo IRC channels reside on Libera.Chat.
--
Quote:
I am NaN! I am a man!
Back to top
View user's profile Send private message
GDH-gentoo
Veteran
Veteran


Joined: 20 Jul 2019
Posts: 1537
Location: South America

PostPosted: Sun Jul 16, 2023 7:29 pm    Post subject: Re: The pain of creating 'universal' shell scripts Reply with quote

Zucca wrote:
Do others here feel the same pain?

Yes. ("Rich" is Rich Felker, musl's lead developer)

Quote:
I am a strong believer that Bourne-derived languages are extremely bad, on the same order of badness as Perl, for programming, and consider programming sh for any purpose other than as a super-portable, lowest common-denominator platform for build or bootstrap scripts and the like, as an extremely misguided endeavor.

_________________
NeddySeagoon wrote:
I'm not a witch, I'm a retired electronics engineer :)
Ionen wrote:
As a packager I just don't want things to get messier with weird build systems and multiple toolchains requirements though :)
Back to top
View user's profile Send private message
szatox
Advocate
Advocate


Joined: 27 Aug 2013
Posts: 3137

PostPosted: Sun Jul 16, 2023 7:37 pm    Post subject: Reply with quote

Quote:
I guess I need to call it with full path of /bin/ps and call it a day.
Except that it may call procps or busybox ps (via symlink), so you're pretty much back to square 1
Back to top
View user's profile Send private message
Zucca
Moderator
Moderator


Joined: 14 Jun 2007
Posts: 3345
Location: Rasi, Finland

PostPosted: Sun Jul 16, 2023 7:51 pm    Post subject: Re: The pain of creating 'universal' shell scripts Reply with quote

GDH-gentoo wrote:
Zucca wrote:
Do others here feel the same pain?

Yes. ("Rich" is Rich Felker, musl's lead developer)
I cannot even begin to guess the amount of times I've referenced that exact site when writing these portable shell scripts. :P

szatox wrote:
Except that it may call procps or busybox ps (via symlink), so you're pretty much back to square 1
Dang. I could then add some extra functions to recognize... While I hate this, I've done once a function to check if awk implementation supports function foo(). I might as well go ahead and go full... retard. :P
_________________
..: Zucca :..
Gentoo IRC channels reside on Libera.Chat.
--
Quote:
I am NaN! I am a man!
Back to top
View user's profile Send private message
stefan11111
l33t
l33t


Joined: 29 Jan 2023
Posts: 922
Location: Romania

PostPosted: Sun Jul 16, 2023 8:05 pm    Post subject: Reply with quote

If portability is the concern, can't you use something like c89?
I imagine you'll have a better time that trying to do this with shell.
_________________
My overlay: https://github.com/stefan11111/stefan_overlay
INSTALL_MASK="/etc/systemd /lib/systemd /usr/lib/systemd /usr/lib/modules-load.d *udev* /usr/lib/tmpfiles.d *tmpfiles* /var/lib/dbus /usr/bin/gdbus /lib/udev"
Back to top
View user's profile Send private message
szatox
Advocate
Advocate


Joined: 27 Aug 2013
Posts: 3137

PostPosted: Sun Jul 16, 2023 8:21 pm    Post subject: Reply with quote

Well, you clearly are already aware of the fact that you're overdoing it, so how 'bout changing the approach a little bit?
It doesn't matter how hard you try, you will never achieve 100% of the objective "script that runs everywhere". Whatever you do, I can always throw you some case where it breaks. E.g. it's not going to work on windows :lol:

Wait, what? What did you say? You mean that windows is out of scope? Ah, right... Well, thank you, that's exactly my point.
What is the purpose of the script you're writing?
What tools are available on the systems to which this script is applicable?
Answering those questions should help define "good enough"... And then just ignore the rest of the world.
Back to top
View user's profile Send private message
Zucca
Moderator
Moderator


Joined: 14 Jun 2007
Posts: 3345
Location: Rasi, Finland

PostPosted: Sun Jul 16, 2023 9:44 pm    Post subject: Reply with quote

szatox wrote:
What is the purpose of the script you're writing?
Not any particular purpose. We're in 'Gentoo Chat' after all. ;)

But sure this started as a thought to script a thingy which runs on user logout. Then it would check which processes user has still running. Finally decides if to empty user temp dirs or not. When I encountered few incompatibilities with different shells and cli tools (once again) I decided to rant here. :P

stefan11111 wrote:
If portability is the concern, can't you use something like c89?
I imagine you'll have a better time that trying to do this with shell.
Most of the times I start to write any code it's usually just some file management stuff. Coding it in C seem a little overkill. And also my C skills are almost non-existent.

Al in all... Shell scripting is a big mess of if foo then bar nested... Most of the shell code I write are oneliners that are only store in shell history file... but sometimes the monster in me breaks free and starts writing more complex shell scripts. :twisted:
_________________
..: Zucca :..
Gentoo IRC channels reside on Libera.Chat.
--
Quote:
I am NaN! I am a man!
Back to top
View user's profile Send private message
geki
Advocate
Advocate


Joined: 13 May 2004
Posts: 2387
Location: Germania

PostPosted: Mon Jul 17, 2023 8:24 pm    Post subject: Reply with quote

Did you try to set ash's terminal width with
Code:
stty columns <number>
Maybe ps' output is readable then?Just a wild guess, not tested. :o
_________________
hear hear
Back to top
View user's profile Send private message
pjp
Administrator
Administrator


Joined: 16 Apr 2002
Posts: 20067

PostPosted: Tue Jul 18, 2023 6:41 pm    Post subject: Re: The pain of creating 'universal' shell scripts Reply with quote

Zucca wrote:
Do others here feel the same pain?
I'm still in the habit of trying to write non-bash scripts, though for a different reasons. Given a broad range of OS versions form multiple vendors of Unix (not Linux), what's the easiest solution? Korn shell.

Zucca wrote:
Sometimes I really think I should just use #!/bin/bash and assume gnu coreutils. *sigh*
I'm kind of the opposite. I'd prefer to not have bash on anything i had to use. Any of the GNU tools, really; Embrace and Extend comes to mind, although that's probably less of an issue than, I'll just leave it at RH/IBMisms.
_________________
Quis separabit? Quo animo?
Back to top
View user's profile Send private message
stefan11111
l33t
l33t


Joined: 29 Jan 2023
Posts: 922
Location: Romania

PostPosted: Tue Jul 18, 2023 7:49 pm    Post subject: Re: The pain of creating 'universal' shell scripts Reply with quote

pjp wrote:

Zucca wrote:
Sometimes I really think I should just use #!/bin/bash and assume gnu coreutils. *sigh*
I'm kind of the opposite. I'd prefer to not have bash on anything i had to use. Any of the GNU tools, really; Embrace and Extend comes to mind, although that's probably less of an issue than, I'll just leave it at RH/IBMisms.

Don't you use bash for portage?
_________________
My overlay: https://github.com/stefan11111/stefan_overlay
INSTALL_MASK="/etc/systemd /lib/systemd /usr/lib/systemd /usr/lib/modules-load.d *udev* /usr/lib/tmpfiles.d *tmpfiles* /var/lib/dbus /usr/bin/gdbus /lib/udev"
Back to top
View user's profile Send private message
geki
Advocate
Advocate


Joined: 13 May 2004
Posts: 2387
Location: Germania

PostPosted: Tue Jul 18, 2023 8:54 pm    Post subject: Reply with quote

I played a bit with my ps tools from busybox and procps-ng. I recommend to use args over comm to get the process command in full length. You can set the width of the columns of the output of ps by setting its header name. :o
Code:
$ busybox ps -Ao user=ThisIsmYLongUserHeader,pid,tty,args
and
Code:
$ ps -Ao user=ThisIsmYLongUserHeader,pid,tty,args

_________________
hear hear
Back to top
View user's profile Send private message
Zucca
Moderator
Moderator


Joined: 14 Jun 2007
Posts: 3345
Location: Rasi, Finland

PostPosted: Wed Jul 19, 2023 8:28 am    Post subject: Re: The pain of creating 'universal' shell scripts Reply with quote

pjp wrote:
I'm still in the habit of trying to write non-bash scripts, though for a different reasons. Given a broad range of OS versions form multiple vendors of Unix (not Linux), what's the easiest solution? Korn shell.
Android uses some korn derivated shell too. Good point.

pjp wrote:
I'm kind of the opposite. I'd prefer to not have bash on anything i had to use. Any of the GNU tools, really; Embrace and Extend comes to mind, although that's probably less of an issue than, I'll just leave it at RH/IBMisms.
Yes bash is a mess, but it's also a some kind of de-facto standard. Many scripting examples in the net have bashisms in them.
I use bash as my interactive shell because... it's fine? I used zsh for about a year. I never really understood it.
I should see what the current shell landscape on Linux is today. I know some are stoked about fish.
bash as the syntax of ebuilds is fine also. Arrays make few things quite simpler.
But usually when I need to write a shell script I'll start with minimal set of sh, usually test run with busybox. Such script should work in most places. That said, sometimes when I write bash It also would run on most places which are not meant to be minimalistic.

stefan11111 wrote:
Don't you use bash for portage?
Portage uses the build system which in its current EAPI version depends on bash to interpret ebuilds. Many users only use emerge command and never really interact with bash.
_________________
..: Zucca :..
Gentoo IRC channels reside on Libera.Chat.
--
Quote:
I am NaN! I am a man!
Back to top
View user's profile Send private message
Zucca
Moderator
Moderator


Joined: 14 Jun 2007
Posts: 3345
Location: Rasi, Finland

PostPosted: Wed Jul 19, 2023 8:47 am    Post subject: Reply with quote

geki wrote:
I played a bit with my ps tools from busybox and procps-ng. I recommend to use args over comm to get the process command in full length. You can set the width of the columns of the output of ps by setting its header name. :o
Code:
$ busybox ps -Ao user=ThisIsmYLongUserHeader,pid,tty,args
and
Code:
$ ps -Ao user=ThisIsmYLongUserHeader,pid,tty,args


Continues in here. :wink:

EDIT: Fixed the link. Thanks pietinger!
_________________
..: Zucca :..
Gentoo IRC channels reside on Libera.Chat.
--
Quote:
I am NaN! I am a man!
Back to top
View user's profile Send private message
flexibeast
Guru
Guru


Joined: 04 Apr 2022
Posts: 324
Location: Naarm/Melbourne, Australia

PostPosted: Thu Jul 20, 2023 2:57 am    Post subject: Re: The pain of creating 'universal' shell scripts Reply with quote

Zucca wrote:
usually when I need to write a shell script I'll start with minimal set of sh

Likewise, unless it's something unlikely to be useful to others, in which case i'm happy to take advantage of zsh's features (although i've kept bash as root's shell, to avoid possibly making Portage unhappy). Using both Linux and OpenBSD makes me want to avoid bashisms, and i've found it educational to write POSIX scripts (e.g. epub-create).
Back to top
View user's profile Send private message
pjp
Administrator
Administrator


Joined: 16 Apr 2002
Posts: 20067

PostPosted: Thu Jul 20, 2023 9:26 pm    Post subject: Re: The pain of creating 'universal' shell scripts Reply with quote

stefan11111 wrote:
Don't you use bash for portage?
Portage does require bash, so i do have it installed if that's what you were asking. I always use #!/bin/sh, though I'm not sure how effective that is. Since I haven't used "not Linux" in a long time, I'm less picky about it. Someday™ I'll try dash. It's installed, but I haven't tested it. i guess that's progress since I've meant to do it years ago but apparently only installed it last November :)


Zucca wrote:
Android uses some korn derivated shell too. Good point.
To clarify, my point was that under "those" circumstances, the only common solution to all of the vendor OSes and versions was ksh93. I was expecting to find that ksh had a a freer license, but it uses EPL. I presumed Android was avoiding bash due to their no GPL policy. EPL 1.0 was apparently not compatible with the GPL, so maybe that was sufficiently "not GPL."

Zucca wrote:
Yes bash is a mess, but it's also a some kind of de-facto standard. Many scripting examples in the net have bashisms in them.
I use bash as my interactive shell because... it's fine?
If you're only targeting bash, then that's fine. I mainly dislike "vendor" lock-in. It's the main reason I use clang (in make files. From the cli I use gcc because it installs a shortcut).

Zucca wrote:
I used zsh for about a year. I never really understood it.
I should see what the current shell landscape on Linux is today. I know some are stoked about fish.
I used plain 'sh' because that's what I needed to maintain systems (excepting when ksh was "better"). I avoided alternatives so that I didn't have too much "how do I do that" going on in the middle of the night.

I believe I tried zsh once, but not seriously. I also tried csh, and wtf? is mostly what I remember of it.

Zucca wrote:
bash as the syntax of ebuilds is fine also. Arrays make few things quite simpler.
But usually when I need to write a shell script I'll start with minimal set of sh, usually test run with busybox. Such script should work in most places. That said, sometimes when I write bash It also would run on most places which are not meant to be minimalistic.
I believe I have used arrays, but I didn't like the syntax (as I recall). I didn't retain "how," so I don't use them. I'm no expert, but what 'sh' can't do, i wonder about the general wisdom that was developing more "maximalistic" alternatives :). Although I don't know what would be a "better" solution (I'm not a fan of code churn *cough*python*cough*).

Someday™ I'll assemble a distro. My plan has been to do so with busybox and toybox. I recently noticed PuppyLinux again, and that seems like a promising starting point.
_________________
Quis separabit? Quo animo?
Back to top
View user's profile Send private message
Zucca
Moderator
Moderator


Joined: 14 Jun 2007
Posts: 3345
Location: Rasi, Finland

PostPosted: Mon Jul 31, 2023 7:24 am    Post subject: is_int? Reply with quote

One silly thing with *nix shells is to check if some variable is an integer. The common way would be
Code:
printf '%d' "$var" > /dev/null 2>&1
... and it works fairly universally, but I found out that on android shell that didn't work. That's really a corner case. Android uses toybox for its core cli utils.
However I managed to find a way that doesn't use printf but uses normal test:
Code:
[ ! -z "${var##*[!0-9]*}" ]

The above code pretty much shows why shell scripting is too complicated. It looks "neat" when it's just one single command, but it twists some brain cells at first look.
Oh and that still has some improvements to do, since it doesn't support signed integers. Oh well...
_________________
..: Zucca :..
Gentoo IRC channels reside on Libera.Chat.
--
Quote:
I am NaN! I am a man!
Back to top
View user's profile Send private message
pjp
Administrator
Administrator


Joined: 16 Apr 2002
Posts: 20067

PostPosted: Mon Jul 31, 2023 6:10 pm    Post subject: Reply with quote

The ${...} machinations are nice, but I can never remember them as I don't use them often. As such, I'll typically only use them when it seems worth the added effort. I've never written (or needed to) a script where performance was a factor. I've written some one-offs that could be improved if they were needed repeatedly, but that's about it.

Another possibility (seems to work with busybox and toybox).
Code:
$ echo 'foo~1%2#3' |grep -e '[^0-9]'
foo~1%2#3

_________________
Quis separabit? Quo animo?
Back to top
View user's profile Send private message
Display posts from previous:   
Reply to topic    Gentoo Forums Forum Index Gentoo Chat All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum