How to properly process and print files with spaces in bash
To illustrate the difference between "$@"
and $@
, let us consider the two following functions:
f() { for i in $@; do echo $i; done; }g() { for i in "$@"; do echo $i; done; }
When calling these function with the parameters a "b c" "d e"
the result will be
- function f
f a "b c" "d e" a b c d e
- function g
g a "b c" "d e" a b c d e
So when "$@" is within double quotes, the expansion keeps each parameter in a separate word (even if the parameter contains one or more space).When $@ (without double quotes) is expanded, a parameter with a space will be considered as two words.
In your script, you need also to surround argdir
and file
with double quotes. It is useful when the name of a directory or a file contains space so the name will be considered as a single value. Below your script modified.
#! /bin/bash -urecls () { # store current working directory # issues: seems bad to have cwd defined up here and used down below in getAbsolutePath -- too much coupling cwd=$PWD # get absolute path of arg argdir=`getAbsolutePath "$@"` # check if it exists if [ ! -e "$argdir" ]; then echo "$argdir does not exist" return 1 fi echo "$argdir exists" # check if it's a directory if [ ! -d "$argdir" ]; then echo "$argdir is not a directory" return 2 fi echo "$argdir is a directory" tab="" recls_internal "$argdir" return 0}recls_internal () { for file in "$@"; do echo -n "$tab${file##/*/}" if [ -d "$file" ]; then # print forward slash to show it's a directory echo "/" savedtab=$tab tab="$tab " recls_internal "$file"/* tab=$savedtab else # if not a directory, print a new line echo "" fi done}getAbsolutePath () { if [ -z ${1##/*} ]; then echo "$1" else echo "$cwd/$1" fi}