I'm trying to write a bash script that read user's input (some files so user can use TAB
completion) and copy them into a specific folder.
#/bin/bash
read -e files
for file in $files
do
echo $file
cp "$file" folder/"$file"
done
It's ok for: file1 file2 ...
Or with : file*
(even if there is a filename with space in the folder).
But it's not working for filenames with space escaped with backslash \
like : file\ with\ space
escaped spaces are ignored and string is split on each spaces, even escaped.
I saw information on quoting, printf, IFS, read and while... I think it's very basic bash script but I can't find a good solution. Can you help me?
Clearing IFS
prior to your unquoted expansion will allow globbing to proceed while preventing string-splitting:
IFS=$' \t\n' read -e -a globs # read glob expressions into an array
IFS=''
for glob in "${globs[@]}"; do # these aren't filenames; don't claim that they are.
files=( $glob ) # expand the glob into filenames
# detect the case where no files matched by checking whether the first result exists
# these *would* need to be quoted, but [[ ]] turns off string-splitting and globbing
[[ -e $files || -L $files ]] || {
printf 'ERROR: Glob expression %q did not match any files!\n' "$glob" >&2
continue
}
printf '%q\n' "${files[@]}" # print one line per file matching
cp -- "${files[@]}" folder/ # copy those files to the target
done
Note that we're enforcing the default IFS=$' \t\n'
during the read
operation, which ensures that unquoted whitespace is treated as a separator between array elements at that stage. Later, with files=( $glob )
, by contrast, we have IFS=''
, so whitespace no longer can break individual names apart.