anselm
anselm

Reputation: 13661

Escaping space in bash script

I am trying to make a script to append all files ending with .hash to be verified by md5deep. Files with space in their name seem to break this script.

#!/bin/bash
XVAR=""
for f in *.hash
do
    XVAR="$XVAR -x $f "
done
md5deep -e $XVAR -r *

Whenever i run the script with a file called "O S.hash" i would get

O: No such file or directory

If i change XVAR="$XVAR -x $f " to XVAR="$XVAR -x \'$f\' " or XVAR="$XVAR -x \"$f\" "

md5deep will interpenetrate the input as "O instead

"O: No such file or directory

an echo of the variable in the script shows XVAR as -x 'O S.hash' or -x "O S.hash"

a manual input of the command in shell such as md5deep -e -x "O S.hash" -r * works but if its in the script the command seems to break

Upvotes: 4

Views: 857

Answers (2)

Jonathan Leffler
Jonathan Leffler

Reputation: 753725

Now you know why people on Unix systems traditionally avoided file names with spaces in them (and directory names likewise) — it is a nuisance (to be polite about it) to have to program the shell to handle such names. The shell was designed for use in systems without such names. Newlines also cause much grief.

With bash, your best solution by far is to use an array to hold the elements, and then "${array[@]}" to list them; it is almost trivial:

declare -a XVAR

for file in *.hash
do
    XVAR+=("-x" "$file")
done

md5deep -e "${XVAR[@]}" -r *

(Exploiting the array extension notation mentioned by Gordon Davisson. See section §6.7 'Arrays' of the bash reference manual (for Bash 4.1) for a lot of array information; see section §3.4 'Shell Parameters' for the += operator.)

If you can't use arrays for some reason, then you need a program that escapes its arguments so that the shell won't distort things. I have such a program, called escape:

XVAR=
for file in *.hash
do
    name=$(escape "$file")
    XVAR="$XVAR -x $file"
done
eval md5deep -e $XVAR -r *

With the eval, it is tricky to use; it works, but use arrays.

Upvotes: 2

Michał Trybus
Michał Trybus

Reputation: 11794

This is not the nicest solution, but is seems it will work:

find . -name '*.hash' -printf "-x\0%p\0" | xargs -0 md5deep -r * -e

This actually doesn't do exactly the same as the OP wanted, so here's a modification as suggested by Tim Pote and Jonathan Leffler:

find . -maxdepth 1 -name '*.hash' -printf "-x\0%p\0" | xargs -0 md5deep -r * -e

Upvotes: 3

Related Questions