0

I was trying to write bash script that will run a command on certain fs events. So far I have succeeded in building fswatch and configuring it, but I cannot get bash to split a string into an array, to then switch case (if that exists) all the different events that I am watching for.

I always get some form of not a valid identifier and I dont even know what that is supposed to mean.

#!/usr/bin/bash

IFS=" "

fswatch -0 -xnr --event 2 --event 4 --event  8 --event 16 --event 128 --event 256 ./ \
| xargs -0 -n 1 -I {path} sh -c "echo {path}; read -a arr {path};"

sh: line 0: read: `/run/media/twiggeh/Storage/projects/Clone/client/src/script.sh': not a valid identifier
5
  • @DavidPostill that tools output doesn't seem to contain any useful information, its mistaking the replacement string for something else it seems
    – Twiggeh
    Sep 6, 2020 at 11:36
  • read -a is a bash extension, not available in sh. Sep 6, 2020 at 13:03
  • @glennjackman: read is found in sh(1) - Linux man page.
    – harrymc
    Sep 6, 2020 at 13:46
  • I think that there is something missing in the path /run/media/twiggeh/Storage/projects/Clone/client/src/script.sh.
    – harrymc
    Sep 6, 2020 at 13:50
  • @harrymc I really only wanted to read the file path as a string into the array. I've managed to do it with arr=($(echo {path} | tr " " "\n")) but I am still curious about why my first approach did not work out.
    – Twiggeh
    Sep 6, 2020 at 13:53

1 Answer 1

1

The not a valid identifier message is telling you that you can't use a file path as a variable name (your code is expanding the read statement to something like read -a arr /path/to/my/directory. You're calling sh, which may not necessarily be a shell such as bash that even understands -a arr (dash, for example, would report dash: 1: read: Illegal option -a). Specify bash if you want bash.

However, I think you would do better to turn your code inside out (as it were). The following is bash code that will handle filenames containing not only whitespace but other strange characters (newline, etc.):

while IFS= read -d '' -r line
do
    # Split at the last space
    file="${line% *}" event="${line##* }"

    # Event and file are now separated
    printf "event=%s, file=%s.\n" "$event" "$file"

    # Put your case statements here
    # case "$event" ... esac

done < <(fswatch -0 -xnr --event 2 --event 4 --event 8 --event 16 --event 128 --event 256 ./)

The redirect from fswatch... allows your main while loop to remain in the parent shell's context, so that any variables you set in the case...esac part remain accessible to the rest of the script. Using the more obvious fswatch ... | while ... do ... done construct would put the while loop into a subshell, preventing any variables it might set from being available in the remainder of the script.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .