0

I've tried a first time with sh like I refer to in my other post here.

I'm trying to run a bash script menu to run from terminal only.

#!/bin/bash

HEIGHT=800 WIDTH=600 CHOICE_HEIGHT=8 BACKTITLE="Installer-menu" TITLE="Setup opions" MENU="Choose one of the following options:"

OPTIONS=$(1 Add Mint PPA and update 2 Install Cinnamon 3 update and upgrade 4 Additional software installation 5 Upgrade Kernel 6 Resolve Ubuntu Cinnamon issues 7 Install graphic proprietary driver x reboot )

RESULT=$(dialog --clear
--backtitle "$BACKTITLE"
--title "$TITLE"
--menu "$MENU"
$HEIGHT $WIDTH $CHOICE_HEIGHT
"${OPTIONS[@]}"
2>&1 >/dev/tty)

case $RESULT in 1) sudo apt-key adv --recv-keys --keyserver keyserver.ubuntu.com A1715D88E1DF1F24 40976EAF437D05B5 3B4FE6ACC0B21F32 A6616109451BBBF2; sudo sh -c 'echo "deb http://packages.linuxmint.com vanessa main upstream import backport romeo" >> /etc/apt/sources.list.d/mint.list'; sudo sh -c 'echo "deb-src http://packages.linuxmint.com vanessa main upstream import backport romeo" >> /etc/apt/sources.list.d/mint.list'; sudo apt-key export 451BBBF2 | gpg --dearmour -o /etc/apt/trusted.gpg.d/mint.gpg; sudo apt update;; 2) sudo apt install slick-greeter muffin cinnamon;; 3) sudo apt update; sudo apt upgrade -y;; 4) sudo sh additional-software.sh;; 5) sudo sh ubuntu-mainline-kernel.sh;; 6) sudo sh problem-solver.sh;; 7) sudo sh nvidia-installation;; *) reboot;; esac

and a smaller one with:

#!/bin/bash

HEIGHT=800 WIDTH=600 CHOICE_HEIGHT=8 BACKTITLE="Installer-menu" TITLE="Package options" MENU="Choose one of the following options:"

OPTIONS=$(1 Install package list 2 Export package list 3 update and upgrade x reboot )

RESULT=$(dialog --clear
--backtitle "$BACKTITLE"
--title "$TITLE"
--menu "$MENU"
$HEIGHT $WIDTH $CHOICE_HEIGHT
"${OPTIONS[@]}"
2>&1 >/dev/tty)

case $RESULT in 1) while IFS= read -r line do echo "apt install -y $line" done < installation.txt;; 2) awk -F'll ' ' /apt install/ && !/nvidia/ && !/--/ && !/-f/{ print $2 } ' /var/log/apt/history.log >installation.txt;; 3) sudo apt update && sudo apt upgrade;; *) reboot;; esac


$ shellcheck myscript
No issues detected!

I think I'm omitting the same thing on both. Both files are running only the last command.

Can someone enlighten me ?

Reference used

I've the help of everyone I was able to run the packages (=bash script filename) menu with inside:

#!/bin/bash

width=72 height=22 menu_height=8 backtitle='Installer-menu' title='Package options' menu='Choose one of the following options:'

options=(1 'Install package list' 2 'Export package list' 3 'update and upgrade' x reboot q quit )

result=$(dialog --clear
--backtitle "$backtitle"
--title "$title"
--menu "$menu"
$height $width $menu_height
"${options[@]}"
2>&1 >/dev/tty)

case "$result" in 1) echo Package Install; sh installpkgs.sh;; 2) echo Manualy installed packages exported; sh pkgsexport.sh;; 3) echo Package upgrade; apt update && apt upgrade -y;; x) echo Reboot; reboot;; q) clear; exit ;; esac

The two sh files contains each:

#!/bin/sh
# Export manualy installed packages 
# Packages installed with apt install from terminal excl.
# Output file: installation.txt

awk -F'll ' ' /apt install/ && !/nvidia/ && !/--/ && !/-f/{ print $2 } ' /var/log/apt/history.log >installation.txt


#!/bin/sh
# Install package list
for pkg in `cat installation.txt`; do sudo apt-get install -y $pkg; done

Resulting in a working menu for all listed options: packages-bash script


For the installer-menu, I've tried to apply it so:

#!/bin/bash

width=72 height=22 menu_height=8 backtitle="Installer-menu" title="Setup opions" menu="Choose one of the following options:"

options=(1 Add Mint PPA and update 2 Install Cinnamon 3 update and upgrade 4 Additional software installation 5 Upgrade Kernel 6 Resolve Ubuntu Cinnamon issues 7 Install graphic proprietary driver x reboot q quit )

result=$(dialog --clear
--backtitle "$backtitle"
--title "$title"
--menu "$menu"
$height $width $menu_height
"${options[@]}"
2>&1 >/dev/tty)

case "$result" in 1) echo 'Mint backport repos installed'; apt-key adv --recv-keys --keyserver keyserver.ubuntu.com A1715D88E1DF1F24 40976EAF437D05B5 3B4FE6ACC0B21F32 A6616109451BBBF2; sh -c 'echo "deb http://packages.linuxmint.com vanessa main upstream import backport romeo" >> /etc/apt/sources.list.d/mint.list'; sh -c 'echo "deb-src http://packages.linuxmint.com vanessa main upstream import backport romeo" >> /etc/apt/sources.list.d/mint.list'; apt-key export 451BBBF2 | gpg --dearmour -o /etc/apt/trusted.gpg.d/mint.gpg; apt update;; 2) echo 'Installation of Cinnamon'; apt install slick-greeter muffin cinnamon;; 3) echo 'Package upgrade'; apt update && apt upgrade -y;; 4) sh additional-software.sh;; 5) sh ubuntu-mainline-kernel.sh;; 6) sh problem-solver.sh;; 7) sh nvidia-installation;; x) echo Reboot; reboot;; q) clear; exit ;; esac

This is how the menu shows up:

Installer-menu

But I forgot to enter every title between ' '

cas
  • 78,579
  • 1
    In your OPTIONS assignment, you appear to be confusing array construction ( ... ) with command substitution $( ... ) – steeldriver Jan 28 '23 at 03:01
  • I do not realy understand, but I also think that it is on tntry RESULT=$ the problem. The menu doesn't even showup. It jumps directly to the last command. Any advice is welcome. @steeldriver –  Jan 28 '23 at 03:06
  • I can see it's also used here, but do not understand it well yet: https://stackoverflow.com/questions/9084257/bash-array-with-spaces-in-elements –  Jan 28 '23 at 03:08
  • so far as I can see, RESULT=$( ... ) is not a problem because you are trying to substitute the output of the dialog command – steeldriver Jan 28 '23 at 03:14
  • @Wingarmac That's the syntax to create an array and to assign values to it, see Arrays. – Freddy Jan 28 '23 at 03:15
  • As others have said, use OPTIONS=( ... ) (without the $) for creating an array. You'll also need to quote each multi-word array element individually, otherwise each word will become a separate element due to the shell's whitespace word-splitting). e.g. OPTIONS=(1 "Add Mint PPA and update" 2 "Install Cinnamon" ...). And remember that dialog's --menu option requires tag (e.g. 1, 2, ...) and item pairs ("Add Mint PPA...", "Install Cinnamon", etc). – cas Jan 28 '23 at 13:35
  • OPTIONS=(...) is for defining an array called OPTIONS. RESULT=$(...) is for executing a program and storing the output in a variable called RESULT (this is called command substitution). BTW, it's generally best not to use all-caps for your own variable names - by convention, all-caps names are for the shell internal variables and exported variables. Best to use options and result instead. – cas Jan 28 '23 at 13:40
  • You are repeatedly missing the most important point about the array. As I said in my answer and in my comments above, multi-word elements of the array need to be quoted. Otherwise each word will be treated as a separate element of the array. – cas Jan 31 '23 at 03:05
  • BTW, why are you running things like sh -c 'echo ...'? You don't need to run echo in a sub-shell, that could be written simply as, e.g., echo "deb http://packages.linuxmint.com vanessa main upstream import backport romeo" >> /etc/apt/sources.list.d/mint.list. Also, if the *.sh scripts being called from the various case statements were executable and had an appropriate #! line, you could just run them as ./script-name.sh rather than sh script-name.sh. And, worth noting, if any of them use arrays or other bash features then they'd need to be run with bash, not sh. – cas Jan 31 '23 at 03:11
  • Also BTW, you don't need a ; at the end of a line. As with any shell commands, on the command-line or in a script, you can separate them with either a ; or a newline. An extra ; doesn't harm anything, but it's not required. The ;; to terminate a case IS required, though, whether there's one command or more. – cas Jan 31 '23 at 03:14
  • One other important point about array elements. It's not only multi-word strings that need to be quoted. Any and all shell metacharacters (including ;, &, >, | and many more) ALL need to be either escaped or quoted. This is not specific to arrays, it's the same whenever you want to use a shell metacharacter as a literal string. If it's not quoted or escaped, the shell will act on it. if it is quoted, the shell will treat it as just another character. – cas Jan 31 '23 at 03:18
  • Please don't replace your question with a finished script. This site is all about Questions and Answers. If you replace the question, then the context of any answers will be lost and the next person searching for a similar question/answer will find it harder to understand the answer. Answers primarily benefit you as the asker, but they're also supposed to benefit those who come later. – cas Jan 31 '23 at 10:01

1 Answers1

0

Here's a (dry-run, echo-only) example of what I was talking about in my comments.

  1. use options=() instead of options=$() to create the array. Array lists and command substitution are not the same thing.
  2. multi-word elements of the array need to be quoted.
  3. lower-case variable names.

Also:

  1. Height and width in dialog are specified in characters, not pixels, so I've used 72x22 instead of 800x600. That's enough to fill most of a "standard" 80x25 screen or terminal. Alternatively, just set them both to 0 and dialog will make the menu as big as it needs to be.
  2. I've also renamed your variable CHOICE_HEIGHT to menu_height, mostly because that's how it's documented in the dialog man page.
  3. Double-quotes are for when you need to interpolate variables etc into strings. Single-quotes are better for fixed strings.
  4. I've added a "quit" option (in addition to the Cancel button provided by dialog --menu) and changed the case statement so that reboot isn't the default option. That's a terrible default, you don't want the machine to reboot if the user makes a mistake, or uses the Cancel button.

The most important items (1 & 2) above were already in the reference example on askubuntu.com that you started from, as was a width and height of 40x15.

#!/bin/bash

width=72 height=22 menu_height=8 backtitle='Installer-menu' title='Package options' menu='Choose one of the following options:'

options=(1 'Install package list' 2 'Export package list' 3 'update and upgrade' x reboot q quit )

result=$(dialog --clear
--backtitle "$backtitle"
--title "$title"
--menu "$menu"
$height $width $menu_height
"${options[@]}"
2>&1 >/dev/tty)

case "$result" in 1) echo while IFS= read -r line ... ;; 2) echo awk -F'll' ... ;; 3) echo 'sudo apt update && sudo apt upgrade' ;; x) echo reboot ;; q) clear; exit ;; esac

cas
  • 78,579
  • When I tried to launch it lke this, I get: packages: 10: Syntax error: "(" unexpected @cas –  Jan 29 '23 at 21:49
  • 1
    Are you using #!/bin/sh (e.g. dash or ash or some ancient proprietary sh) instead of #!/bin/bash? Arrays aren't supported in posix-only sh, arrays are an enhanced feature that require enhanced shells like bash or ksh or zsh. – cas Jan 29 '23 at 23:52
  • I'm feeling so silly now ... @cas –  Jan 30 '23 at 09:59
  • For the treatment of the results, could you give a full line entry example for 1) echo while ... ? @cas –  Jan 30 '23 at 10:04
  • I get these results packages: line 26: syntax error near unexpected tokendo' packages: line 26: do'when I choose for point ´3)- Maybe I should put this command between()`? It isn't clear to me. @cas –  Jan 30 '23 at 10:07
  • For the case statements, you could probably just copy and paste them from yours to replace my echo examples. Each case can have one or more shell statements (separated by ;), and is terminated by two semi-colons (no spaces between them, just ;;). 2. All options ran fine on my system (I tested it thoroughly before posting) - I suspect you've made a typo somewhere, maybe a single semi-colon rather than double on either case 2 or case 3. Using (1), (2), (3) etc for case statements is only a cosmetic difference from just 1), 2), 3), etc. The leading ( is optional.
  • – cas Jan 30 '23 at 10:46
  • BTW, I would rewrite your while read -r line... loop as just apt install -y $(cat installation.txt). Package names can't contain whitespace or shell metacharacters so, as long as that file contains ONLY valid package names (and is small enough to fit in the maximum command line length, about 2 million characters on linux. Debian/Ubuntu/Mint/etc don't have anywhere near enough package names to exceed that - the average pkg name is < 15 chars), it will be safe to run like that. It will also run much faster because it only needs to fork apt once rather than once for every package. – cas Jan 30 '23 at 10:56
  • I just checked and the average package name length is 17.38 characters: apt-cache search . | awk '{total += length($1); count++};END{printf "%i / %i = %.2f\n", total, count, total/count}' on my Debian Sid system outputs 1237423 / 71185 = 17.38. With an average length of 17.38, it would take over 115,000 packages to exceed ARG_MAX, and Debian currently has only 71,185. It will be several years at least before that's a problem. – cas Jan 30 '23 at 11:10
  • also BTW, with your installations.txt file, you seem to be reinventing the --get-selections and --set-selections that have been implemented in dpkg for decades. To save: dpkg --get-selections '*' > selections.txt (the single-quoted * is important, otherwise it won't include the status of packages that aren't installed). And to restore (on the same system, or on a different system), dpkg --set-selections < selections.txt. That tells dpkg what the system should have installed, then you run apt dist-upgrade to install/uninstall the packages as per the selections.txt file. – cas Jan 30 '23 at 11:16
  • I only want the package names of those I entered manualy with the apt install command. Not apt-get. That's the way I install software official software on ubuntu. Exceptions done for snap install spotify and packages installed from other sources with wget and dpkg -i - Thus this is all depending on your own needs. i've a small list of some 10 packages I export in that file. @cas –  Jan 30 '23 at 12:56
  • This last point is clearly out of subject. At is not the export package list the question here. But the bash script menu and the launch of every entry of it. –  Jan 30 '23 at 12:58