2

I have a bash script that does something like this:

java -jar executablefile.jar --width 100 --speed 50 --ouput outfile.mp4 --input file1.dat file2.dat file3.dat (etc)

I am able to read all the files in the directory like so:

dir=~/location/to/files
for f in "$dir"/*; do
   echo "$f"
done

The above test shows all the files. So I can get one file at a time into $f. However I need to (probably in that loop) concatinate each filename string (including path I believe) into a variable that I can use like so:

java -jar executablefile.jar --width 100 --speed 50 --ouput outfile.mp4 --input $listOfFileNamesWithSpaceBetweenEachFile I can't for the life of me find anything like this. Does anyone have any suggestion?

Thank you.

UPDATE Further to communication, it turns out I was a little wrong. It needs to be something like this:

-- input /path/to/filename1.gpx --input /path/to/filename2.gpx --input /path/to/filename3.gpx etc

So I was able to get a string via the following:

VAR=""
dir=~/location/to/files
for f in "$dir"/*; do
    echo ${f}
    VAR+="--input ${f} "
done
`

Thank you everyone for your help!

robster
  • 121
  • Do you really need spaces in e.g. --input = file1.dat file2.dat file3.dat? Do you want this to be a single command line argument or separate arguments --input = file1.dat file2.dat file3.dat. Please [edit] your question to add this information/clarification. – Bodo Jan 31 '22 at 13:25
  • The program works with java ... --input foo.dat bar.dat, and doesn't need e.g. java ... --input foo.dat --input bar.dat? – ilkkachu Jan 31 '22 at 13:33
  • Please explain why you (think you) need a variable that contains all file names. Would java -jar executablefile.jar --width 100 --speed 50 --ouput outfile.mp4 --input "$dir"/file*.dat work? – Bodo Jan 31 '22 at 15:05
  • thank you for this help. I was able to find the solution and have update the original question with details at the bottom. – robster Jan 31 '22 at 21:37

1 Answers1

4

If you run this on the shell command line:

somecommand --input file1.dat file2.dat file3.dat 

then somecommand will get 4 arguments, --input and the three filenames. You could do the same with

somecommand --input file*.dat

the glob file*.dat will expand to a list of the filenames, each in a separate argument to somecommand.

So,

java ... --input ~/location/to/files/*

may or may not be all you need to do.


Now, you could have a variable like var="foo.txt bar.txt" and use it unquoted to use it as a crappy list, but that's going to be trouble the very moment some filename contains whitespace (or worse).

Instead, use an array:

files=(foo.txt bar.txt)
somecommand --input "${files[@]}"

or

files=(foo*.txt) # expands each filename to a distinct array element.
somecommand --input "${files[@]}"

See How can we run a command stored in a variable? for other details, incl. incrementally building the array.


In an edit you said that the command needs --input file1 --input file2 ... instead, as is usual for how command line options with arguments work.

In that case, you'll need to build the arguments in an array like this:

args=()
dir=~/location/to/files
for f in "$dir"/*; do
   args+=(--input "$f")
done

and again run the command as

somecommand ... "${args[@]}"
ilkkachu
  • 138,973
  • thank you for this help. I was able to find the solution and have update the original question with details at the bottom.

    Interestingly the software won't take a command *.DAT and take all DAT files. It needs a --input filename.DAT for each one. Crazy, but there it is.

    – robster Jan 31 '22 at 21:38
  • @robster, no, the program taking --input file1 --input file2 etc. (or --input=file1 --input?file2) is the usual behaviour. --input there is an option that takes an option-argument, and anything after that would be a normal non-option argument. E.g. with grep, while you can give multiple patterns to it, something like grep -e pattern1 pattern2 filename wouldn't work, it couldn't know which args are patterns and which are filenames. So, you need grep -e pattern1 -e pattern2 filename. And remember it's the shell that expands globs, so --input *.dat can't work. – ilkkachu Feb 01 '22 at 11:51
  • of course, the program probably should just take the list of input filenames as non-option args, and nix the --input option entirely. Then you'd use java ... --width 100 --speed 50 --output outfile.mp4 file1.dat file2.dat file3.dat or java ... --width 100 --speed 50 --output outfile.mp4 file*.dat – ilkkachu Feb 01 '22 at 11:52
  • @robster, but, seriously, if you're using Bash (or ksh or zsh), stop using strings as arrays, the shells have actual arrays too. Filenames can contain any character, including whitespace (and quotes), and there's no way to shove multiple arbitrary filenames in a single string with just word splitting. (And no, putting quotes there doesn't work.) Storing multiple distinct items of the same type is exactly what arrays exist for. – ilkkachu Feb 01 '22 at 11:57