How to pass the content of a file as multiple arguments in bash

14,649

Solution 1

"$(cat mydata)" evaluates to a string which contains the content of the file mydata minus any trailing newline. What you want is the list of whitespace-separated words in the file. So, for once, use the command substitution outside of double quotes:

myscript.sh $(cat mydata)

For extra robustness, turn off globbing, so that if a column in mydata contains one of the characters \[*? it isn't interpreted as a file name pattern. You may also want to set IFS to contain the word separator characters, but the default (ASCII whitespace) should be exactly what you need.

(set -f; myscript.sh $(cat mydata))

Alternatively, you could use the read builtin. This reads the first line and ignores the rest (which you could do above by replacing cat by head -n 1).

read -r one two three rest <mydata
myscript.sh "$one" "$two" "$three"

Solution 2

That's typically what xargs is for:

xargs myscript.sh < mydata

xargs considers the input as blank or newline separated words where single quote, double quote or backslash is used to escape the separators. xargs will run the command as many times as necessary so as to avoid the limit on the size of arguments (and environment) passed to a command.

Solution 3

Instead of passing as multiple arguments, I just pass the arguments as a single array and then do whatever I want with the arguments.

#This is the function which takes a variable length array as an input. 
function function_call() 
{
    all_array_values=$1[@]
    a=("${!all_array_values}")
    for i in "${a[@]}" ; do
        echo "$i"
    done
}


#Here I add all the file contents to the variable named input.  
input=$(cat filename)
#In this step I convert the file contents to an array by splitting on space. 
input_to_array=(${input//' '/ })
#I call the function here. 
function_call input_to_array

Testing

I have the input file as below.

cat filename
1 2 3 4
5
6
7
8

As you can see, I have used multiple lines as well in the input for testing purposes.

Now, when I run the above script, I get the below output.

1
2
3
4
5
6
7
8

I change the input file to have lesser number of arguments and when I run with the lesser arguments, I get the below output.

1
2
3
4

References

https://stackoverflow.com/questions/16461656/bash-how-to-pass-array-as-an-argument-to-a-function https://stackoverflow.com/a/5257398/1742825

Share:
14,649
michelemarcon
Author by

michelemarcon

Hello, I'm a Java software engineer. I also have some Android and Linux experience.

Updated on September 18, 2022

Comments

  • michelemarcon
    michelemarcon almost 2 years

    I have a file that contains data that gets updated over time (mydata). The file looks like this:

    1 2 3
    

    With this file, I want to do this (basically handle each number as a separate parameter):

    myscript.sh 1 2 3
    

    Since the data is not static but instead updated over time, I want to run this command:

    myscript.sh "$(cat mydata)"
    

    But instead I see ./myscript.sh: line 1: 1: command not found

    What should I do?

    • muru
      muru over 9 years
      And what does your script contain, since that's an error from within the script?
    • michelemarcon
      michelemarcon over 9 years
      sqlite3 /data.db "insert into tbl1 (v1, v2, v3, timeEnter) values($1 $2, $3, DATETIME('NOW'));"
    • michelemarcon
      michelemarcon over 9 years
      Solved! I didn't put the directive #!/bin/bash and was running from sh instead...
    • muru
      muru over 9 years
      Still makes me wonder what in it caused 1 to be treated as a command. I don't see process or command substitutions.
    • mikeserv
      mikeserv over 9 years
      Split cat's output on IFS. set -f; unset IFS; myscript.sh $(cat mydata)
  • mikeserv
    mikeserv over 9 years
    And by the way - there is robust and there is bugged - there is no extra robust. Your recommendation is, in any case, bugged as it does not consider $IFS's current value in either case and relies upon a shell default - (or, it would, if it didn't contradict itself instead) which is a default you have no way of knowing remains still in effect.
  • Stéphane Chazelas
    Stéphane Chazelas over 7 years
    Note that the default $IFS is only space, tab and newline/linefeed (and NUL with zsh), not the other ASCII whitespace (vertical tab, carriage return, form feed). Some shells take $IFS from the environment which allows system distributors or administrators to set a different default value (though that's rarely done).
  • Shicheng Guo
    Shicheng Guo about 3 years
    How to handle it if mydata have multiple rows? current command only take the 1st row.
  • Stéphane Chazelas
    Stéphane Chazelas about 3 years
    @ShichengGuo, what do you mean by row? If you mean line, then as I said newline is one of the characters xargs treats as delimiter, so if mydata contains foo bar\nbaz\n, your command will be passed foo, bar and baz as arguments.