Create bash script that allows you to choose multiple options instead of just one?
I'm thinking about creating a bash script where multiple options can be specified and at the end define the variables according to the chosen options or execute certain orders when receiving the different options. An example is worth more than a thousand words:
[X] Copy only (1) - Options typed by the user
[ ] Move only (2)
[X] Checksum (3) - Options typed by the user
[ ] Reset permission (4)
[ ] Exit (5)
Select choice:
I have found some options but I do not know how to make them do a certain function because I do not understand how the code works.
Update:
Code functional:
#!/bin/bash
#Contributing code by Sergiy Kolodyazhnyy and adaptation for MarianoM.
resize -s 40 90 > /dev/null #Change window size.
option=$(dialog --clear --backtitle "Synchronization..." --title "Synchronize"
--checklist "Select the synchronization options:" 20 50 10
checksum "Compare the content" off
detail "Show more information" off
directory "Synchronize folders" on
recursive "Include subfolders" off 2>&1 > /dev/tty)
for i in $option; do #Set parameter of the menu options.
case $i in
checksum) c="-c" ;;
detail) v="-v" ;;
directory) d="-d" ;;
recursive) r="-r" ;;
esac
done
if [ -z $option ]; then #Check if the variable is empty. If it is empty, it means that the user has not chosen an option.
clear
echo
echo "Error: No option has been selected or dialog not installed. The program can not continue."
echo
else
clear
source=$(dialog --clear --backtitle "Please select source..." --title "Source:" --fselect "" 20 50 2>&1 > /dev/tty)
if [ -z $source ]; then
clear
echo
echo "Error program. Source not selected, try again!"
echo
exit
fi
clear
destination=$(dialog --clear --backtitle "Please select destination..." --title "Destination:" --fselect "" 20 50 2>&1 > /dev/tty)
if [ -z $destination ]; then
clear
echo
echo "Error program. Destination not selected, try again!"
echo
exit
fi
clear
rsync "$c" "$v" "$d" "$r" "$source" "$destination"
echo
fi
exit
bash scripts
|
show 4 more comments
I'm thinking about creating a bash script where multiple options can be specified and at the end define the variables according to the chosen options or execute certain orders when receiving the different options. An example is worth more than a thousand words:
[X] Copy only (1) - Options typed by the user
[ ] Move only (2)
[X] Checksum (3) - Options typed by the user
[ ] Reset permission (4)
[ ] Exit (5)
Select choice:
I have found some options but I do not know how to make them do a certain function because I do not understand how the code works.
Update:
Code functional:
#!/bin/bash
#Contributing code by Sergiy Kolodyazhnyy and adaptation for MarianoM.
resize -s 40 90 > /dev/null #Change window size.
option=$(dialog --clear --backtitle "Synchronization..." --title "Synchronize"
--checklist "Select the synchronization options:" 20 50 10
checksum "Compare the content" off
detail "Show more information" off
directory "Synchronize folders" on
recursive "Include subfolders" off 2>&1 > /dev/tty)
for i in $option; do #Set parameter of the menu options.
case $i in
checksum) c="-c" ;;
detail) v="-v" ;;
directory) d="-d" ;;
recursive) r="-r" ;;
esac
done
if [ -z $option ]; then #Check if the variable is empty. If it is empty, it means that the user has not chosen an option.
clear
echo
echo "Error: No option has been selected or dialog not installed. The program can not continue."
echo
else
clear
source=$(dialog --clear --backtitle "Please select source..." --title "Source:" --fselect "" 20 50 2>&1 > /dev/tty)
if [ -z $source ]; then
clear
echo
echo "Error program. Source not selected, try again!"
echo
exit
fi
clear
destination=$(dialog --clear --backtitle "Please select destination..." --title "Destination:" --fselect "" 20 50 2>&1 > /dev/tty)
if [ -z $destination ]; then
clear
echo
echo "Error program. Destination not selected, try again!"
echo
exit
fi
clear
rsync "$c" "$v" "$d" "$r" "$source" "$destination"
echo
fi
exit
bash scripts
@Sergiy Kolodyazhnyy Thank you anyway. I already found what I was looking for here: serverfault.com/a/506704/500213
– MarianoM
Jan 4 at 3:37
I've reopened the question. The linked post and what you've provided both useselectstatement, so in such regard it's duplicate. However since you want to provide multiple options at the same time, it's not quite a duplicate. What can be done, however, is to allowselectstatement to loop through multiple options and execute each one after the other. I would also caution against providing multiple options at the same time, since if you try to provide options like2,1,3- well the file will be moved, and next two options will fail due to missing file.
– Sergiy Kolodyazhnyy
Jan 4 at 4:01
@Sergiy Kolodyazhnyy Thanks for reopening, I will delete the comment about it. I still do not understand programming too much, that's why I published the way I came up with it. Obviously it is a bad idea and there are better solutions provided as the link that I have left. Although I still can not understand how they work and how to set variables according to the selected options.
– MarianoM
Jan 4 at 4:08
1
You useage of bach variables is surprising.c=$(echo "-c")can be simply writtenc="-c". But your problem is thatvaluevariable: since you lump everything into one variable (that you quote to pass to rsync), rsync sees one single parameter string ("-c -v -d -r") that it cannot parse. Use the individual$c/$d/$v/$rvariables directly in the rsync call.
– xenoid
Jan 7 at 13:38
1
Printing doesn't tell everything: "a b"` and "a b" print the same but are different, one is one single value, the other is two. Tryfor x in "a b";do echo $x;donev.s.for x in "a" "b";do echo $x;done.
– xenoid
Jan 7 at 13:48
|
show 4 more comments
I'm thinking about creating a bash script where multiple options can be specified and at the end define the variables according to the chosen options or execute certain orders when receiving the different options. An example is worth more than a thousand words:
[X] Copy only (1) - Options typed by the user
[ ] Move only (2)
[X] Checksum (3) - Options typed by the user
[ ] Reset permission (4)
[ ] Exit (5)
Select choice:
I have found some options but I do not know how to make them do a certain function because I do not understand how the code works.
Update:
Code functional:
#!/bin/bash
#Contributing code by Sergiy Kolodyazhnyy and adaptation for MarianoM.
resize -s 40 90 > /dev/null #Change window size.
option=$(dialog --clear --backtitle "Synchronization..." --title "Synchronize"
--checklist "Select the synchronization options:" 20 50 10
checksum "Compare the content" off
detail "Show more information" off
directory "Synchronize folders" on
recursive "Include subfolders" off 2>&1 > /dev/tty)
for i in $option; do #Set parameter of the menu options.
case $i in
checksum) c="-c" ;;
detail) v="-v" ;;
directory) d="-d" ;;
recursive) r="-r" ;;
esac
done
if [ -z $option ]; then #Check if the variable is empty. If it is empty, it means that the user has not chosen an option.
clear
echo
echo "Error: No option has been selected or dialog not installed. The program can not continue."
echo
else
clear
source=$(dialog --clear --backtitle "Please select source..." --title "Source:" --fselect "" 20 50 2>&1 > /dev/tty)
if [ -z $source ]; then
clear
echo
echo "Error program. Source not selected, try again!"
echo
exit
fi
clear
destination=$(dialog --clear --backtitle "Please select destination..." --title "Destination:" --fselect "" 20 50 2>&1 > /dev/tty)
if [ -z $destination ]; then
clear
echo
echo "Error program. Destination not selected, try again!"
echo
exit
fi
clear
rsync "$c" "$v" "$d" "$r" "$source" "$destination"
echo
fi
exit
bash scripts
I'm thinking about creating a bash script where multiple options can be specified and at the end define the variables according to the chosen options or execute certain orders when receiving the different options. An example is worth more than a thousand words:
[X] Copy only (1) - Options typed by the user
[ ] Move only (2)
[X] Checksum (3) - Options typed by the user
[ ] Reset permission (4)
[ ] Exit (5)
Select choice:
I have found some options but I do not know how to make them do a certain function because I do not understand how the code works.
Update:
Code functional:
#!/bin/bash
#Contributing code by Sergiy Kolodyazhnyy and adaptation for MarianoM.
resize -s 40 90 > /dev/null #Change window size.
option=$(dialog --clear --backtitle "Synchronization..." --title "Synchronize"
--checklist "Select the synchronization options:" 20 50 10
checksum "Compare the content" off
detail "Show more information" off
directory "Synchronize folders" on
recursive "Include subfolders" off 2>&1 > /dev/tty)
for i in $option; do #Set parameter of the menu options.
case $i in
checksum) c="-c" ;;
detail) v="-v" ;;
directory) d="-d" ;;
recursive) r="-r" ;;
esac
done
if [ -z $option ]; then #Check if the variable is empty. If it is empty, it means that the user has not chosen an option.
clear
echo
echo "Error: No option has been selected or dialog not installed. The program can not continue."
echo
else
clear
source=$(dialog --clear --backtitle "Please select source..." --title "Source:" --fselect "" 20 50 2>&1 > /dev/tty)
if [ -z $source ]; then
clear
echo
echo "Error program. Source not selected, try again!"
echo
exit
fi
clear
destination=$(dialog --clear --backtitle "Please select destination..." --title "Destination:" --fselect "" 20 50 2>&1 > /dev/tty)
if [ -z $destination ]; then
clear
echo
echo "Error program. Destination not selected, try again!"
echo
exit
fi
clear
rsync "$c" "$v" "$d" "$r" "$source" "$destination"
echo
fi
exit
bash scripts
bash scripts
edited Jan 7 at 17:19
MarianoM
asked Jan 4 at 2:41
MarianoMMarianoM
6810
6810
@Sergiy Kolodyazhnyy Thank you anyway. I already found what I was looking for here: serverfault.com/a/506704/500213
– MarianoM
Jan 4 at 3:37
I've reopened the question. The linked post and what you've provided both useselectstatement, so in such regard it's duplicate. However since you want to provide multiple options at the same time, it's not quite a duplicate. What can be done, however, is to allowselectstatement to loop through multiple options and execute each one after the other. I would also caution against providing multiple options at the same time, since if you try to provide options like2,1,3- well the file will be moved, and next two options will fail due to missing file.
– Sergiy Kolodyazhnyy
Jan 4 at 4:01
@Sergiy Kolodyazhnyy Thanks for reopening, I will delete the comment about it. I still do not understand programming too much, that's why I published the way I came up with it. Obviously it is a bad idea and there are better solutions provided as the link that I have left. Although I still can not understand how they work and how to set variables according to the selected options.
– MarianoM
Jan 4 at 4:08
1
You useage of bach variables is surprising.c=$(echo "-c")can be simply writtenc="-c". But your problem is thatvaluevariable: since you lump everything into one variable (that you quote to pass to rsync), rsync sees one single parameter string ("-c -v -d -r") that it cannot parse. Use the individual$c/$d/$v/$rvariables directly in the rsync call.
– xenoid
Jan 7 at 13:38
1
Printing doesn't tell everything: "a b"` and "a b" print the same but are different, one is one single value, the other is two. Tryfor x in "a b";do echo $x;donev.s.for x in "a" "b";do echo $x;done.
– xenoid
Jan 7 at 13:48
|
show 4 more comments
@Sergiy Kolodyazhnyy Thank you anyway. I already found what I was looking for here: serverfault.com/a/506704/500213
– MarianoM
Jan 4 at 3:37
I've reopened the question. The linked post and what you've provided both useselectstatement, so in such regard it's duplicate. However since you want to provide multiple options at the same time, it's not quite a duplicate. What can be done, however, is to allowselectstatement to loop through multiple options and execute each one after the other. I would also caution against providing multiple options at the same time, since if you try to provide options like2,1,3- well the file will be moved, and next two options will fail due to missing file.
– Sergiy Kolodyazhnyy
Jan 4 at 4:01
@Sergiy Kolodyazhnyy Thanks for reopening, I will delete the comment about it. I still do not understand programming too much, that's why I published the way I came up with it. Obviously it is a bad idea and there are better solutions provided as the link that I have left. Although I still can not understand how they work and how to set variables according to the selected options.
– MarianoM
Jan 4 at 4:08
1
You useage of bach variables is surprising.c=$(echo "-c")can be simply writtenc="-c". But your problem is thatvaluevariable: since you lump everything into one variable (that you quote to pass to rsync), rsync sees one single parameter string ("-c -v -d -r") that it cannot parse. Use the individual$c/$d/$v/$rvariables directly in the rsync call.
– xenoid
Jan 7 at 13:38
1
Printing doesn't tell everything: "a b"` and "a b" print the same but are different, one is one single value, the other is two. Tryfor x in "a b";do echo $x;donev.s.for x in "a" "b";do echo $x;done.
– xenoid
Jan 7 at 13:48
@Sergiy Kolodyazhnyy Thank you anyway. I already found what I was looking for here: serverfault.com/a/506704/500213
– MarianoM
Jan 4 at 3:37
@Sergiy Kolodyazhnyy Thank you anyway. I already found what I was looking for here: serverfault.com/a/506704/500213
– MarianoM
Jan 4 at 3:37
I've reopened the question. The linked post and what you've provided both use
select statement, so in such regard it's duplicate. However since you want to provide multiple options at the same time, it's not quite a duplicate. What can be done, however, is to allow select statement to loop through multiple options and execute each one after the other. I would also caution against providing multiple options at the same time, since if you try to provide options like 2,1,3 - well the file will be moved, and next two options will fail due to missing file.– Sergiy Kolodyazhnyy
Jan 4 at 4:01
I've reopened the question. The linked post and what you've provided both use
select statement, so in such regard it's duplicate. However since you want to provide multiple options at the same time, it's not quite a duplicate. What can be done, however, is to allow select statement to loop through multiple options and execute each one after the other. I would also caution against providing multiple options at the same time, since if you try to provide options like 2,1,3 - well the file will be moved, and next two options will fail due to missing file.– Sergiy Kolodyazhnyy
Jan 4 at 4:01
@Sergiy Kolodyazhnyy Thanks for reopening, I will delete the comment about it. I still do not understand programming too much, that's why I published the way I came up with it. Obviously it is a bad idea and there are better solutions provided as the link that I have left. Although I still can not understand how they work and how to set variables according to the selected options.
– MarianoM
Jan 4 at 4:08
@Sergiy Kolodyazhnyy Thanks for reopening, I will delete the comment about it. I still do not understand programming too much, that's why I published the way I came up with it. Obviously it is a bad idea and there are better solutions provided as the link that I have left. Although I still can not understand how they work and how to set variables according to the selected options.
– MarianoM
Jan 4 at 4:08
1
1
You useage of bach variables is surprising.
c=$(echo "-c") can be simply written c="-c". But your problem is that value variable: since you lump everything into one variable (that you quote to pass to rsync), rsync sees one single parameter string ("-c -v -d -r") that it cannot parse. Use the individual $c/$d/$v/$r variables directly in the rsync call.– xenoid
Jan 7 at 13:38
You useage of bach variables is surprising.
c=$(echo "-c") can be simply written c="-c". But your problem is that value variable: since you lump everything into one variable (that you quote to pass to rsync), rsync sees one single parameter string ("-c -v -d -r") that it cannot parse. Use the individual $c/$d/$v/$r variables directly in the rsync call.– xenoid
Jan 7 at 13:38
1
1
Printing doesn't tell everything: "a b"` and "a b" print the same but are different, one is one single value, the other is two. Try
for x in "a b";do echo $x;done v.s. for x in "a" "b";do echo $x;done.– xenoid
Jan 7 at 13:48
Printing doesn't tell everything: "a b"` and "a b" print the same but are different, one is one single value, the other is two. Try
for x in "a b";do echo $x;done v.s. for x in "a" "b";do echo $x;done.– xenoid
Jan 7 at 13:48
|
show 4 more comments
1 Answer
1
active
oldest
votes
From the discussion in the comments it is apparent that your main concern is to create as script with multiple selections, rather than focus on copying/moving files themselves, and the file operations are just an example. This functionality can be achieved via dialog command, which allows creating text user interfaces, with --checklist flag specifically; however there's nothing in the standard shell-only toolbox to achieve what you want. Hence, dialog is an appropriate tool for this job.
Below you will find an example script. While the script implements only 3
options that were discussed, it provides a decent starting point which users can extent further, and also addresses mutually exclusive options as mentioned in the comments. Particularly, the multiple selection is addressed in menu() function, which serves as a wrapper for dialog with --checklist option
To keep things simple, all you really need is this:
output=$(dialog --clear --backtitle "Backtitle. Use <SPACE> to select." --title "My Dialog"
--checklist "Select all that apply" 50 50 100
checksum "SHA-256" off
copy "Copy only (exclusive with move)" off
move "Move only (exclusive with copy)" off 2>&1 > /dev/tty)
This saves the selection of multiple items to variable $output. Note that `2>&1 > /dev/tty) at the end are crucial to saving the return value into variable. But see the script below for more practical example:
#!/bin/bash
puke(){
# function to exit with specific error message
# analogous to 'die' in Perl
printf ">>> Errors were encountered: %sn" "$1" && exit
} > /dev/stderr
menu(){
# dialog --help documents the option as follows:
# --checklist <text> <height> <width> <list height> <tag1> <item1> <status1>...
# tags are what the output returns.
# We can use word-splitting
# and iterate over output of this function in order. Of course first option
# being checksum will always work and is not mutually exclusive with anything else
dialog --clear --backtitle "Backtitle. Use <SPACE> to select." --title "My Dialog"
--checklist "Select all that apply" 50 50 100
checksum "SHA-256" off
copy "Copy only (exclusive with move)" off
move "Move only (exclusive with copy)" off || puke
} 2>&1 1>/dev/tty
select_file(){
dialog --backtitle "Choose file by typing or navigating and selecting with <SPACE>" --fselect "/etc/"
20 50 || puke
} 2>&1 1>/dev/tty
iter_actions(){
# variables are available to child functions
# Since we call iter_actions in main(), this
# function also knows about main's variable $fselect
for i ; do
case "$i" in
checksum) sha256sum "$fselect" ;;
copy) cp "$fselect" /tmp ;;
move) mv "$fselect" /tmp ;;
esac
done
}
main(){
# here I'm using /etc but you can use $PWD to default to user's
# current working directory, or accept positional parameters from command-line
# as in $1, $2 and so forth
fselect=$( select_file "/etc" )
actions=$(menu)
printf "r%b" "33c" # this clear the screen
case "$actions" in
*copy*move|*move*copy) puke "Mutually exclusive options selected" ;;
*) iter_actions $actions ;; # note here variable is unquoted on purpose
esac
}
# script entry point
main "$@"
For further research:
- How can I create a select menu in a shell script?
- How to get dialog box input directed to a variable?
- Why write an entire bash script in functions?
2
+1.dialogis a good tool, that works well in text screens as well as in terminal windows, and it looks good, even if it is a text mode tool. It is also a good idea to let functions do the job, and have a small main program :-)
– sudodus
Jan 4 at 9:13
Thank you very much Sergiy! There are still parts of his code that I have not been able to understand, and I will continue investigating it. I do not have too advanced knowledge in programming, but I know something and I want to learn. I have updated the question with the code that I have managed to understand and I have managed to make it functional. But it still presents a problem, in the question it says what it is about.
– MarianoM
Jan 7 at 13:28
I would like it if possible, also recommend me what to improve the code.
– MarianoM
Jan 7 at 13:30
Thanks for everything @Sergiy Kolodyazhnyy. Finally I managed to make it functional after some recommendations from another user.
– MarianoM
Jan 7 at 17:32
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "89"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2faskubuntu.com%2fquestions%2f1106787%2fcreate-bash-script-that-allows-you-to-choose-multiple-options-instead-of-just-on%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
From the discussion in the comments it is apparent that your main concern is to create as script with multiple selections, rather than focus on copying/moving files themselves, and the file operations are just an example. This functionality can be achieved via dialog command, which allows creating text user interfaces, with --checklist flag specifically; however there's nothing in the standard shell-only toolbox to achieve what you want. Hence, dialog is an appropriate tool for this job.
Below you will find an example script. While the script implements only 3
options that were discussed, it provides a decent starting point which users can extent further, and also addresses mutually exclusive options as mentioned in the comments. Particularly, the multiple selection is addressed in menu() function, which serves as a wrapper for dialog with --checklist option
To keep things simple, all you really need is this:
output=$(dialog --clear --backtitle "Backtitle. Use <SPACE> to select." --title "My Dialog"
--checklist "Select all that apply" 50 50 100
checksum "SHA-256" off
copy "Copy only (exclusive with move)" off
move "Move only (exclusive with copy)" off 2>&1 > /dev/tty)
This saves the selection of multiple items to variable $output. Note that `2>&1 > /dev/tty) at the end are crucial to saving the return value into variable. But see the script below for more practical example:
#!/bin/bash
puke(){
# function to exit with specific error message
# analogous to 'die' in Perl
printf ">>> Errors were encountered: %sn" "$1" && exit
} > /dev/stderr
menu(){
# dialog --help documents the option as follows:
# --checklist <text> <height> <width> <list height> <tag1> <item1> <status1>...
# tags are what the output returns.
# We can use word-splitting
# and iterate over output of this function in order. Of course first option
# being checksum will always work and is not mutually exclusive with anything else
dialog --clear --backtitle "Backtitle. Use <SPACE> to select." --title "My Dialog"
--checklist "Select all that apply" 50 50 100
checksum "SHA-256" off
copy "Copy only (exclusive with move)" off
move "Move only (exclusive with copy)" off || puke
} 2>&1 1>/dev/tty
select_file(){
dialog --backtitle "Choose file by typing or navigating and selecting with <SPACE>" --fselect "/etc/"
20 50 || puke
} 2>&1 1>/dev/tty
iter_actions(){
# variables are available to child functions
# Since we call iter_actions in main(), this
# function also knows about main's variable $fselect
for i ; do
case "$i" in
checksum) sha256sum "$fselect" ;;
copy) cp "$fselect" /tmp ;;
move) mv "$fselect" /tmp ;;
esac
done
}
main(){
# here I'm using /etc but you can use $PWD to default to user's
# current working directory, or accept positional parameters from command-line
# as in $1, $2 and so forth
fselect=$( select_file "/etc" )
actions=$(menu)
printf "r%b" "33c" # this clear the screen
case "$actions" in
*copy*move|*move*copy) puke "Mutually exclusive options selected" ;;
*) iter_actions $actions ;; # note here variable is unquoted on purpose
esac
}
# script entry point
main "$@"
For further research:
- How can I create a select menu in a shell script?
- How to get dialog box input directed to a variable?
- Why write an entire bash script in functions?
2
+1.dialogis a good tool, that works well in text screens as well as in terminal windows, and it looks good, even if it is a text mode tool. It is also a good idea to let functions do the job, and have a small main program :-)
– sudodus
Jan 4 at 9:13
Thank you very much Sergiy! There are still parts of his code that I have not been able to understand, and I will continue investigating it. I do not have too advanced knowledge in programming, but I know something and I want to learn. I have updated the question with the code that I have managed to understand and I have managed to make it functional. But it still presents a problem, in the question it says what it is about.
– MarianoM
Jan 7 at 13:28
I would like it if possible, also recommend me what to improve the code.
– MarianoM
Jan 7 at 13:30
Thanks for everything @Sergiy Kolodyazhnyy. Finally I managed to make it functional after some recommendations from another user.
– MarianoM
Jan 7 at 17:32
add a comment |
From the discussion in the comments it is apparent that your main concern is to create as script with multiple selections, rather than focus on copying/moving files themselves, and the file operations are just an example. This functionality can be achieved via dialog command, which allows creating text user interfaces, with --checklist flag specifically; however there's nothing in the standard shell-only toolbox to achieve what you want. Hence, dialog is an appropriate tool for this job.
Below you will find an example script. While the script implements only 3
options that were discussed, it provides a decent starting point which users can extent further, and also addresses mutually exclusive options as mentioned in the comments. Particularly, the multiple selection is addressed in menu() function, which serves as a wrapper for dialog with --checklist option
To keep things simple, all you really need is this:
output=$(dialog --clear --backtitle "Backtitle. Use <SPACE> to select." --title "My Dialog"
--checklist "Select all that apply" 50 50 100
checksum "SHA-256" off
copy "Copy only (exclusive with move)" off
move "Move only (exclusive with copy)" off 2>&1 > /dev/tty)
This saves the selection of multiple items to variable $output. Note that `2>&1 > /dev/tty) at the end are crucial to saving the return value into variable. But see the script below for more practical example:
#!/bin/bash
puke(){
# function to exit with specific error message
# analogous to 'die' in Perl
printf ">>> Errors were encountered: %sn" "$1" && exit
} > /dev/stderr
menu(){
# dialog --help documents the option as follows:
# --checklist <text> <height> <width> <list height> <tag1> <item1> <status1>...
# tags are what the output returns.
# We can use word-splitting
# and iterate over output of this function in order. Of course first option
# being checksum will always work and is not mutually exclusive with anything else
dialog --clear --backtitle "Backtitle. Use <SPACE> to select." --title "My Dialog"
--checklist "Select all that apply" 50 50 100
checksum "SHA-256" off
copy "Copy only (exclusive with move)" off
move "Move only (exclusive with copy)" off || puke
} 2>&1 1>/dev/tty
select_file(){
dialog --backtitle "Choose file by typing or navigating and selecting with <SPACE>" --fselect "/etc/"
20 50 || puke
} 2>&1 1>/dev/tty
iter_actions(){
# variables are available to child functions
# Since we call iter_actions in main(), this
# function also knows about main's variable $fselect
for i ; do
case "$i" in
checksum) sha256sum "$fselect" ;;
copy) cp "$fselect" /tmp ;;
move) mv "$fselect" /tmp ;;
esac
done
}
main(){
# here I'm using /etc but you can use $PWD to default to user's
# current working directory, or accept positional parameters from command-line
# as in $1, $2 and so forth
fselect=$( select_file "/etc" )
actions=$(menu)
printf "r%b" "33c" # this clear the screen
case "$actions" in
*copy*move|*move*copy) puke "Mutually exclusive options selected" ;;
*) iter_actions $actions ;; # note here variable is unquoted on purpose
esac
}
# script entry point
main "$@"
For further research:
- How can I create a select menu in a shell script?
- How to get dialog box input directed to a variable?
- Why write an entire bash script in functions?
2
+1.dialogis a good tool, that works well in text screens as well as in terminal windows, and it looks good, even if it is a text mode tool. It is also a good idea to let functions do the job, and have a small main program :-)
– sudodus
Jan 4 at 9:13
Thank you very much Sergiy! There are still parts of his code that I have not been able to understand, and I will continue investigating it. I do not have too advanced knowledge in programming, but I know something and I want to learn. I have updated the question with the code that I have managed to understand and I have managed to make it functional. But it still presents a problem, in the question it says what it is about.
– MarianoM
Jan 7 at 13:28
I would like it if possible, also recommend me what to improve the code.
– MarianoM
Jan 7 at 13:30
Thanks for everything @Sergiy Kolodyazhnyy. Finally I managed to make it functional after some recommendations from another user.
– MarianoM
Jan 7 at 17:32
add a comment |
From the discussion in the comments it is apparent that your main concern is to create as script with multiple selections, rather than focus on copying/moving files themselves, and the file operations are just an example. This functionality can be achieved via dialog command, which allows creating text user interfaces, with --checklist flag specifically; however there's nothing in the standard shell-only toolbox to achieve what you want. Hence, dialog is an appropriate tool for this job.
Below you will find an example script. While the script implements only 3
options that were discussed, it provides a decent starting point which users can extent further, and also addresses mutually exclusive options as mentioned in the comments. Particularly, the multiple selection is addressed in menu() function, which serves as a wrapper for dialog with --checklist option
To keep things simple, all you really need is this:
output=$(dialog --clear --backtitle "Backtitle. Use <SPACE> to select." --title "My Dialog"
--checklist "Select all that apply" 50 50 100
checksum "SHA-256" off
copy "Copy only (exclusive with move)" off
move "Move only (exclusive with copy)" off 2>&1 > /dev/tty)
This saves the selection of multiple items to variable $output. Note that `2>&1 > /dev/tty) at the end are crucial to saving the return value into variable. But see the script below for more practical example:
#!/bin/bash
puke(){
# function to exit with specific error message
# analogous to 'die' in Perl
printf ">>> Errors were encountered: %sn" "$1" && exit
} > /dev/stderr
menu(){
# dialog --help documents the option as follows:
# --checklist <text> <height> <width> <list height> <tag1> <item1> <status1>...
# tags are what the output returns.
# We can use word-splitting
# and iterate over output of this function in order. Of course first option
# being checksum will always work and is not mutually exclusive with anything else
dialog --clear --backtitle "Backtitle. Use <SPACE> to select." --title "My Dialog"
--checklist "Select all that apply" 50 50 100
checksum "SHA-256" off
copy "Copy only (exclusive with move)" off
move "Move only (exclusive with copy)" off || puke
} 2>&1 1>/dev/tty
select_file(){
dialog --backtitle "Choose file by typing or navigating and selecting with <SPACE>" --fselect "/etc/"
20 50 || puke
} 2>&1 1>/dev/tty
iter_actions(){
# variables are available to child functions
# Since we call iter_actions in main(), this
# function also knows about main's variable $fselect
for i ; do
case "$i" in
checksum) sha256sum "$fselect" ;;
copy) cp "$fselect" /tmp ;;
move) mv "$fselect" /tmp ;;
esac
done
}
main(){
# here I'm using /etc but you can use $PWD to default to user's
# current working directory, or accept positional parameters from command-line
# as in $1, $2 and so forth
fselect=$( select_file "/etc" )
actions=$(menu)
printf "r%b" "33c" # this clear the screen
case "$actions" in
*copy*move|*move*copy) puke "Mutually exclusive options selected" ;;
*) iter_actions $actions ;; # note here variable is unquoted on purpose
esac
}
# script entry point
main "$@"
For further research:
- How can I create a select menu in a shell script?
- How to get dialog box input directed to a variable?
- Why write an entire bash script in functions?
From the discussion in the comments it is apparent that your main concern is to create as script with multiple selections, rather than focus on copying/moving files themselves, and the file operations are just an example. This functionality can be achieved via dialog command, which allows creating text user interfaces, with --checklist flag specifically; however there's nothing in the standard shell-only toolbox to achieve what you want. Hence, dialog is an appropriate tool for this job.
Below you will find an example script. While the script implements only 3
options that were discussed, it provides a decent starting point which users can extent further, and also addresses mutually exclusive options as mentioned in the comments. Particularly, the multiple selection is addressed in menu() function, which serves as a wrapper for dialog with --checklist option
To keep things simple, all you really need is this:
output=$(dialog --clear --backtitle "Backtitle. Use <SPACE> to select." --title "My Dialog"
--checklist "Select all that apply" 50 50 100
checksum "SHA-256" off
copy "Copy only (exclusive with move)" off
move "Move only (exclusive with copy)" off 2>&1 > /dev/tty)
This saves the selection of multiple items to variable $output. Note that `2>&1 > /dev/tty) at the end are crucial to saving the return value into variable. But see the script below for more practical example:
#!/bin/bash
puke(){
# function to exit with specific error message
# analogous to 'die' in Perl
printf ">>> Errors were encountered: %sn" "$1" && exit
} > /dev/stderr
menu(){
# dialog --help documents the option as follows:
# --checklist <text> <height> <width> <list height> <tag1> <item1> <status1>...
# tags are what the output returns.
# We can use word-splitting
# and iterate over output of this function in order. Of course first option
# being checksum will always work and is not mutually exclusive with anything else
dialog --clear --backtitle "Backtitle. Use <SPACE> to select." --title "My Dialog"
--checklist "Select all that apply" 50 50 100
checksum "SHA-256" off
copy "Copy only (exclusive with move)" off
move "Move only (exclusive with copy)" off || puke
} 2>&1 1>/dev/tty
select_file(){
dialog --backtitle "Choose file by typing or navigating and selecting with <SPACE>" --fselect "/etc/"
20 50 || puke
} 2>&1 1>/dev/tty
iter_actions(){
# variables are available to child functions
# Since we call iter_actions in main(), this
# function also knows about main's variable $fselect
for i ; do
case "$i" in
checksum) sha256sum "$fselect" ;;
copy) cp "$fselect" /tmp ;;
move) mv "$fselect" /tmp ;;
esac
done
}
main(){
# here I'm using /etc but you can use $PWD to default to user's
# current working directory, or accept positional parameters from command-line
# as in $1, $2 and so forth
fselect=$( select_file "/etc" )
actions=$(menu)
printf "r%b" "33c" # this clear the screen
case "$actions" in
*copy*move|*move*copy) puke "Mutually exclusive options selected" ;;
*) iter_actions $actions ;; # note here variable is unquoted on purpose
esac
}
# script entry point
main "$@"
For further research:
- How can I create a select menu in a shell script?
- How to get dialog box input directed to a variable?
- Why write an entire bash script in functions?
edited Jan 4 at 6:03
answered Jan 4 at 5:55
Sergiy KolodyazhnyySergiy Kolodyazhnyy
71.3k9147313
71.3k9147313
2
+1.dialogis a good tool, that works well in text screens as well as in terminal windows, and it looks good, even if it is a text mode tool. It is also a good idea to let functions do the job, and have a small main program :-)
– sudodus
Jan 4 at 9:13
Thank you very much Sergiy! There are still parts of his code that I have not been able to understand, and I will continue investigating it. I do not have too advanced knowledge in programming, but I know something and I want to learn. I have updated the question with the code that I have managed to understand and I have managed to make it functional. But it still presents a problem, in the question it says what it is about.
– MarianoM
Jan 7 at 13:28
I would like it if possible, also recommend me what to improve the code.
– MarianoM
Jan 7 at 13:30
Thanks for everything @Sergiy Kolodyazhnyy. Finally I managed to make it functional after some recommendations from another user.
– MarianoM
Jan 7 at 17:32
add a comment |
2
+1.dialogis a good tool, that works well in text screens as well as in terminal windows, and it looks good, even if it is a text mode tool. It is also a good idea to let functions do the job, and have a small main program :-)
– sudodus
Jan 4 at 9:13
Thank you very much Sergiy! There are still parts of his code that I have not been able to understand, and I will continue investigating it. I do not have too advanced knowledge in programming, but I know something and I want to learn. I have updated the question with the code that I have managed to understand and I have managed to make it functional. But it still presents a problem, in the question it says what it is about.
– MarianoM
Jan 7 at 13:28
I would like it if possible, also recommend me what to improve the code.
– MarianoM
Jan 7 at 13:30
Thanks for everything @Sergiy Kolodyazhnyy. Finally I managed to make it functional after some recommendations from another user.
– MarianoM
Jan 7 at 17:32
2
2
+1.
dialog is a good tool, that works well in text screens as well as in terminal windows, and it looks good, even if it is a text mode tool. It is also a good idea to let functions do the job, and have a small main program :-)– sudodus
Jan 4 at 9:13
+1.
dialog is a good tool, that works well in text screens as well as in terminal windows, and it looks good, even if it is a text mode tool. It is also a good idea to let functions do the job, and have a small main program :-)– sudodus
Jan 4 at 9:13
Thank you very much Sergiy! There are still parts of his code that I have not been able to understand, and I will continue investigating it. I do not have too advanced knowledge in programming, but I know something and I want to learn. I have updated the question with the code that I have managed to understand and I have managed to make it functional. But it still presents a problem, in the question it says what it is about.
– MarianoM
Jan 7 at 13:28
Thank you very much Sergiy! There are still parts of his code that I have not been able to understand, and I will continue investigating it. I do not have too advanced knowledge in programming, but I know something and I want to learn. I have updated the question with the code that I have managed to understand and I have managed to make it functional. But it still presents a problem, in the question it says what it is about.
– MarianoM
Jan 7 at 13:28
I would like it if possible, also recommend me what to improve the code.
– MarianoM
Jan 7 at 13:30
I would like it if possible, also recommend me what to improve the code.
– MarianoM
Jan 7 at 13:30
Thanks for everything @Sergiy Kolodyazhnyy. Finally I managed to make it functional after some recommendations from another user.
– MarianoM
Jan 7 at 17:32
Thanks for everything @Sergiy Kolodyazhnyy. Finally I managed to make it functional after some recommendations from another user.
– MarianoM
Jan 7 at 17:32
add a comment |
Thanks for contributing an answer to Ask Ubuntu!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2faskubuntu.com%2fquestions%2f1106787%2fcreate-bash-script-that-allows-you-to-choose-multiple-options-instead-of-just-on%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
@Sergiy Kolodyazhnyy Thank you anyway. I already found what I was looking for here: serverfault.com/a/506704/500213
– MarianoM
Jan 4 at 3:37
I've reopened the question. The linked post and what you've provided both use
selectstatement, so in such regard it's duplicate. However since you want to provide multiple options at the same time, it's not quite a duplicate. What can be done, however, is to allowselectstatement to loop through multiple options and execute each one after the other. I would also caution against providing multiple options at the same time, since if you try to provide options like2,1,3- well the file will be moved, and next two options will fail due to missing file.– Sergiy Kolodyazhnyy
Jan 4 at 4:01
@Sergiy Kolodyazhnyy Thanks for reopening, I will delete the comment about it. I still do not understand programming too much, that's why I published the way I came up with it. Obviously it is a bad idea and there are better solutions provided as the link that I have left. Although I still can not understand how they work and how to set variables according to the selected options.
– MarianoM
Jan 4 at 4:08
1
You useage of bach variables is surprising.
c=$(echo "-c")can be simply writtenc="-c". But your problem is thatvaluevariable: since you lump everything into one variable (that you quote to pass to rsync), rsync sees one single parameter string ("-c -v -d -r") that it cannot parse. Use the individual$c/$d/$v/$rvariables directly in the rsync call.– xenoid
Jan 7 at 13:38
1
Printing doesn't tell everything: "a b"` and "a b" print the same but are different, one is one single value, the other is two. Try
for x in "a b";do echo $x;donev.s.for x in "a" "b";do echo $x;done.– xenoid
Jan 7 at 13:48