1

Nothing I've tried works. Look at the grep to array lines in the script below. Escaping seems to do nothing. But if I make a statically assigned array It's fine.

Such as:

files=(somefile.txt
some\ other\ file.pdf
"yet another file.txt")

This does not work:

#!/bin/bash
find . -name "$1" |
(
        cat - > /tmp/names
        file -N --mime-type --files-from /tmp/names
) |
(
        cat - > /tmp/mimes
#       files=("$(grep -o '^[^:]*' /tmp/mimes)") #one element array
#       files=($(grep -o '^[^:]*' /tmp/mimes)) #files with spaces end up split in to several elements
#       files=($(grep -o '^[^:]*' /tmp/mimes | sed 's/ /\\ /g')) #same but with \ terminated strings
        files=($(grep -o '^[^:]*' /tmp/mimes | cat <(echo '"') - <(echo '"')))
        mimes=($(grep -o '[^:]*$' /tmp/mimes))

        total=${#files[*]}
        for (( i=0; i<=$(( $total -1 )); i++ ))
                do
                echo Mime: "${mimes[$i]}" File: "${files[$i]}"
        done
        printf "$i\n"
)

Edit: Clarification

file /tmp/mimes contains:

./New Text.txt: text/plain

If I grep it to get every thing before the ":"

grep -o '^[^:]*' /tmp/mimes

it outputs: ./New Text.txt

I want to put this output into an array, but it has a space, so I escape the space using sed.

files=($(grep -o '^[^:]*' /tmp/mimes | sed 's/ /\\ /g'))

This does not work. I end up with files[0] = "./New\" and files[1] = "Text.txt"

My question is why doesn't escaping the space work?

If I do:

files=(./New\ Text.txt)

It does work however files[0] = "./New Text.txt" Why does escaping when you do it manually work but when it's the output of grep and sed it doesn't work. It seems like the behaviour of creating an array is inconsistent.

closed as unclear what you're asking by Gilles, techraf, Michael Homer, countermode, HalosGhost Nov 20 '16 at 2:30

Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • I have no idea what you're trying to do. Provide some sample input and desired output. And read our reference question on quoting first; I think your mental model of how quotes work is wrong (cat <(echo '"') - <(echo '"') adds a " character to the beginning the first item and one to the end of the last item, which is probably not what you meant), but it's hard to tell. – Gilles Nov 20 '16 at 0:14
  • In bash, you should be able to read newline-separated data into an array directly using mapfile e.g. grep -o . . . | mapfile -t mimes – steeldriver Nov 20 '16 at 0:15
  • @Gilles Input looks like this ./Game play mechanics.doc: application/msword ./Email List.doc: application/msword ./Get going Email.doc: application/msword ./Map.doc: application/msword ./FTP.doc: application/msword ./GameGossip game development project.doc: application/msword the array files should then contain [./Game play mechanics.doc, ./Email List.doc, ./Get going Email.doc, ./Map.doc, ./FTP.doc, ./GameGossip game development project.doc] and mimes should contain "application/msword" six times. – Geo R Nov 20 '16 at 1:05
  • @steeldriver: mapfile breaks at newline (and doesn't mangle) but piping to mapfile runs in a subshell which discards the var unless you have and use lastpipe (4.2 IIRC). mapfile... < <(grep...) should work on any bash. – dave_thompson_085 Nov 20 '16 at 12:40
0

If you want to separate file names by newlines, set IFS to $'\n' and turn off globbing:

set -f
IFS=$'\n' files=($(grep -o '^[^:]*' /tmp/mimes))
set +f

Note that it breaks if your filenames contain newlines (in addition to colons, which break due to the way you extract the names with grep).

  • That seems to work. But I'm still curious why escaping spaces with '\ ' doesn't work. – Geo R Nov 20 '16 at 2:20
  • 1
    It may also break if any filename contains globbing chars ? * [..] depending on your shell's settings. For bash consider mapfile as per steeldriver's comment on Q. @GeoR: shell or shell-like quoting only works for the script (including partially in unquoted heredocs) and certain commands that do it explicitly like read and xargs, but not for data in general. – dave_thompson_085 Nov 20 '16 at 12:41
  • 1
    @GeoR Because escaping characters with backslash is something in shell script syntax. It isn't something that expansion of unquoted command substitutions does – Gilles Nov 20 '16 at 13:05

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