A disclaimer: This isn't related to one specific command like ls or grep, although I use them in the examples, this is more a bash thing.
Let's say I want to see the file sizes, timestamps, and permissions/owner/group on a set of files (ls -l) that all contain "a certain word". Typically I'd do this:
ls -l $( grep -l 'a certain word' * )
And that works like magic until any of the file names contain a space, like a file named "file name". Then ls can't find what it thinks are two file names, "file" and "name".
Bash scripts have a familiar way of solving a variant of this problem, if you pass file names in on the command line to a script, they are referenced as ${1}, ${2}, etc. And if you wrap them in quotes, i.e. "${1}", "${2}", then if they have spaces you don't have a problem and you can even process all the file names at once by using "${@}" which will correctly list each of the parameters, and keep them intact even if they have spaces - I just haven't found such a mechanism for the grep/ls style problem I list above. If you wrap the expansion command, $( )
with quotes it treats all the files as one big parameter for the ls.
I've usually worked around it with something like grep -l .... | while read file; do ls -l "${file}"; done
, but I really shouldn't have to do that. And doing that still doesn't allow things like sorting the files by date/size/etc (i.e. ls -ltr $( grep -l ....)
)
I keep thinking bash has a solution for this and I just haven't came across it yet and this problem only surfaces once in a while and I usually work around it, but it's now bugged me enough I think there must be a way.
And yes, I've seen the following, they are either questions solved by the specific tool being used (like tar), or the answers are "sorry, you can't get to there from here" because their question is command-specific. I'm asking for handling any space-embedded file name(s) given as results to be passed as parameters to another command, not more while or find magic to solve this issue. I would rather this question sit unanswered (a testament that there isn't a solution) rather than have any of the not-the-same-thing questions offered:
eval
... assuming no filename has an embedded CR.eval ls -l -- $(grep -l ... | sed -e 's/"/\\"/g' -e 's/^/"/' -e 's/$/"/')
- A bit nasty, though!IFS=$'\n' f=( $( grep -l 'find me' * ) ) ; ls -latr "${f[@]}"