0

When I save a command output which contains several lines to a variable directly into my terminal, I have the following results :

$ dirs=$(ls -1d /mnt/*/)
$ echo $dirs
/mnt/ext4/ /mnt/local/ /mnt/remote/ /mnt/test/
$ echo "$dirs"
/mnt/ext4/
/mnt/local/
/mnt/remote/
/mnt/test/

However when using it from a posix shell script the result is different. Here is the script

#!/bin/sh

dirs=$(ls -1d $1)
echo "inline"
echo $dirs
echo "multiline"
echo "$dirs"

And here is the script output

$ ./test.sh /mnt/*/
inline
/mnt/ext4/
multiline
/mnt/ext4/

This happens even if I use bash instead of sh.

Does anyone know how I could save the output of ls -1d /mnt/*/ into a variable keeping the full output ?
I would like to parse each of the four directory paths inside a for loop.

  • The important question here is: what are you going to do with those filenames the script receives as arguments? I'm about 95 % sure that you don't actually want to concatenate them to a single string, but would be better off just looping over the arguments as given. – ilkkachu Jan 18 '18 at 15:24
  • Basically it's for separate the name of the directory and the path itself to create a single variable containing something like ` -x <name1> <path1> -x <name2> <path2> -x <name3> <path3> ...`. It's done now ;) The answer was so obvious I didn't realize immediately that /mnt/*/ was expanded as separate arguments.... – Arkaik Jan 18 '18 at 15:29
5
$ ./test.sh /mnt/*/

The glob here expands to the directory names as separate arguments, same as if you wrote them out manually on the command line:

$ ./test.sh /mnt/ext4/ /mnt/local/ /mnt/remote/ /mnt/test/

However, in the script itself, you refer to only the first argument, $1:

dirs=$(ls -1d $1)

If you want to refer to all the arguments, use "$@" (with the quotes).

However, all you're doing with the directory names here is to run ls on them, which just prints the same names out (though on separate lines). So, if you just want the list of the arguments as a string, you don't need to run the ls command at all, just assign dirs="$@".

Nevertheless, in most, if not all cases it's better to just keep the list of file names in the positional parameters, and loop over them with

for f in "$@"; do ...

or

for f
do ...

Note that file names might contain white space, and when you concatenate the names to a single string, you lose the meaning of the whitespace within the names. foo bar doo might be three files, or the two files foo bar and doo.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.