Hi I fork and customize (https://www.putorius.net/create-multiple-choice-menu-bash.html). It is part of automated building script for my project. I wonder how to redirect the answer to different lines (e.g Debian building script starts in line 20 etc.) instead splitting into various files?
#!/bin/sh
PS3='Choose your building platform: '
OS=("Debian" "Fedora" "Arch Linux" "Quit")
select fav in "${OS[@]}"; do
case $fav in
"Debian")
/bin/sh debian.sh
;;
"Fedora")
/bin/sh fedora.sh
;;
"Arch Linux")
/bin/sh arch_linux.sh
;;
"Quit")
echo "Aborting..."
exit
;;
*) echo "invalid option $REPLY";;
esac
done
Because it comes handy that you can write the code in single file instead of splitting into multiple files.
CodePudding user response:
You can define shell functions:
#!/bin/sh
custom_function () {
echo 'custom_function called !'
}
custom_function
In your case you can define three different functions, one for each build target and then call them:
#!/bin/sh
target_debian () {
echo 'debian'
}
target_fedora () {
echo 'fedora'
}
target_arch () {
echo 'arch'
}
PS3='Choose your building platform: '
OS=("Debian" "Fedora" "Arch Linux" "Quit")
select fav in "${OS[@]}"; do
case $fav in
"Debian")
target_debian
;;
"Fedora")
target_fedora
;;
"Arch Linux")
target_arch
;;
"Quit")
echo "Aborting..."
exit
;;
*) echo "invalid option $REPLY";;
esac
done
Source: https://www.tutorialspoint.com/unix/unix-shell-functions.htm
CodePudding user response:
One approach is to set some flag. Something like:
#!/usr/bin/env bash
Arch_flag=0
Debian_flag=0
Fedora_flag=0
PS3='Choose your building platform: '
OS=("Debian" "Fedora" "Arch Linux" "Quit")
select fav in "${OS[@]}"; do
case $fav in
"Debian")
Debian_flag=1
break
;;
"Fedora")
Fedora_flag=1
break
;;
"Arch Linux")
Arch_flag=1
break
;;
"Quit")
echo "Aborting..."
exit
;;
*) echo "invalid option $REPLY";;
esac
done
if ((Debian_flag)); then
printf 'Do something with %s\n' Debian
fi
if ((Fedora_flag)); then
printf 'Do something with %s\n' Fedora
fi
if ((Arch_flag)); then
printf 'Do something with %s\n' Arch
fi
Or depending on the use case one can embed the flag in the loop.
#!/usr/bin/env bash
PS3='Choose your building platform: '
OS=("Debian" "Fedora" "Arch Linux" "Quit")
select fav in "${OS[@]}"; do
Arch_flag=0
Debian_flag=0
Fedora_flag=0
case $fav in
"Debian")
Debian_flag=1
;;
"Fedora")
Fedora_flag=1
;;
"Arch Linux")
Arch_flag=1
;;
"Quit")
echo "Aborting..."
exit
;;
*) echo "invalid option $REPLY";;
esac
if ((Debian_flag)); then
printf 'Do something with %s\n' Debian
fi
if ((Fedora_flag)); then
printf 'Do something with %s\n' Fedora
fi
if ((Arch_flag)); then
printf 'Do something with %s\n' Arch
fi
done
CodePudding user response:
I *VERY STRONGLY* encourage you to pay attention to William Pursell's comments
, and use areop-enap's functions solution, or Jetchisel's simple blocks, both of which are quite straightforward and elegant. Do not fall into the trap of embedding for the sake of whimsy.
If you want to include several files in one file, use a tool like tar
. If it has to be an executable, try zip
.
There are, however, some (few) cases where being able to have a script completely contain an entire data file is useful.
For those RARE times when another entire file needs to be encoded into your script, put the files in something like base64-encoding. Decode the ones you need to their own files at runtime, or even to a pipe. (Do NOT use offsets. I've had to deal with that nightmare...)
The code below only parses the files it needs. If you ask for "perl" it won't even hit the section with the embedded bash file. (I'm not sure of how the interpreter might pre-parse and optimize, but I don't think this method will allocate retained memory the way assigning these to variables would.)
The one advantage to this method is that it lets you embed arbitrary executables such as compiled C code right into the script, but that is at best a somewhat dubious advantage...
$: ls -l
total 1
-rwxr-xr-x 1 paul 1049089 398 Dec 12 08:54 tst
$: for arg in bash perl; do ./tst $arg; done
./file1_bash this is the bash file
./file2_perl this one is perl
$: ls -l
total 3
-rwxr-xr-x 1 paul 1049089 62 Dec 12 08:56 file1_bash
-rwxr-xr-x 1 paul 1049089 51 Dec 12 08:56 file2_perl
-rwxr-xr-x 1 paul 1049089 398 Dec 12 08:54 tst
$: cat file1_bash
#! /usr/bin/bash
echo "${BASH_SOURCE:-$0}" "$@"
$: cat file2_perl
#! /usr/bin/perl
print join ' ', $0, @ARGV, "\n";
$: cat tst
#! /usr/bin/bash
case $1 in
bash) base64 -d <<< "
IyEgL3Vzci9iaW4vYmFzaAplY2hvICIke0JBU0hfU09VUkNFOi0kMH0iICIkQCIgCg==
" > file1_bash && chmod x ./file1_bash && ./file1_bash this is the bash file ;;
perl) base64 -d <<< "
IyEgL3Vzci9iaW4vcGVybApwcmludCBqb2luICcgJywgJDAsIEBBUkdWLCAiXG4iOyAK
" > file2_perl && chmod x ./file2_perl && ./file2_perl this one is perl ;;
esac
There are a lot of other issues to address -
- it can take a lot of time to decode big files, though scripts should be ok
- if you are dealing with various OS's, be careful about paths, syntax, etc
- make sure you properly copy the base64 into your file without corruption such as indentation
- make sure the target system has the right tools to decode and run the scripts
- ensure proper file locations and permissions when created
- consider cleaning up after yourself if you don't need to leave them for later use
You get the idea.
For the record, in case it matters, this was done on GitBash under windows. Your version might have to make a few refinements.