6

I'm new with shell programming. My goal is to give the user a selection which file should be run. I catch all available scripts in one var with:

var=$(find script*)

so far so good, this is the output:

    echo $var
    script1 script2 script3 scr...

now I want to store each file in a singel variable to run it in later selection

select SEL in script1 script2 script3 ..........
case $SEL in
        $Script1) echo ($Script1 will start) && ./$script1 ;;
        $Script2) echo ($Script2 will start) && ./$script2 ;;
        $Script3) echo ($Script3 will start) && ./$script3 ;;
        $Sc..) echo ($Scr.... will start) && ./$scrip.... ;;
        $Sc...) echo ($Sc...... will start) && ./$scrip..... ;;
        *) echo "choose on of the availabel files";;
    esac
done

I don't have a clue how should I should separate all files if I don't know how many and the exactly length of each file.

I tried to split with echo ${var[1]} and echo $var[1] but this dosn't work. I recive either a empty output or the whole string.

2
  • What is it that you exactly want to achieve? It sounds like an XY problem to me. meta.stackexchange.com/questions/66377/what-is-the-xy-problem
    – Bernhard
    Commented Jun 25, 2014 at 9:13
  • find script* doesn't make sense: it lists files matching script* in the current directory, and if any of these is a subdirectory, its contents is listed recursively. Did you mean to use files matching script* directly in the current directory? Or files with matching names in the current directory or its subdirectories and so on recursively? Commented Jun 25, 2014 at 23:30

2 Answers 2

6

Your first line:

var=$(find script*)

is just making var a single string variable with all of script* in it. It's not an array, so we can't index into it with [] like you want.

The script* is actually expanded by the shell, so find isn't doing anything there (unless they're directories, which it doesn't look like they are) — it just gets all the filenames as arguments, checks they exist, and prints them straight back out again. The shell actually does all the work..

Instead, we can make an array, and we can use the shell's glob expansion directly to populate it:

files=(script*)

When we put the initialiser (the right-hand side of the =) in parentheses we're making an array, which holds multiple values separately. script* will expand to every filename starting with script in the current directory. If there are spaces in the filenames they won't cause the words to be split up the way they would be with commands (backticks or $()) inside the array initialiser.

At this point we can read in some user input:

select SEL in "${files[@]}"
do
    if ! [ "$SEL" ]
    then
        echo "Choose one of the available files."
        continue
    fi
    echo "$SEL will start"
    "./$SEL"
    break
done

We write "${files[@]}" to expand our entire array of filenames cleanly to give to select. The user will be offered a choice of files, and then we enter the do...done block.

If $SEL is empty, the user chose a non-existent entry, so we print the prompt and continue so they're asked to choose again.

Otherwise, we echo the notification that the script will start and run the script. We quote the name "./$SEL" in case the script name has spaces in it, which would otherwise cause the command name to be treated as ./firstword, with the remaining words as arguments. break stops us going back around and asking the user again; if you want to do that, take it out.


The case...of you were using doesn't seem to have much effect in the example you give, but if you do have some separate behaviour depending on the script chosen (and it has to be in this script), you can put that inside the do...done block.

1
  • (script*) only works for bash. Commented Jun 16, 2017 at 12:23
1

Not 100% sure I completely understand what you want to do but this could work better for you: Instead of var=$(find script*) and a case you could better use

for i in `find script*`
do
        echo ($i will start) 
        ./$i
done
1
  • This lists all files matching script* plus the content of any matching directory, recursively. Confusing as the question may be, this behavior isn't useful and is clearly not what was intended. Furthermore that won't work if any of the matching files contain whitespace or globbing characters. The loop should probably be either for i in script* (files in the current directory, done right) or for i in $(find -name 'script*') (looking for files in subdirectories recursively, but done wrong since it chokes on whitespace and globbing characters). Commented Jun 25, 2014 at 23:29

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .