You will have to quote the name of the file:
awk 'BEGIN {
filename = "path to file with spaces"
"file \"" filename "\"" | getline
print
}'
or, as suggested in comments, for ease of reading,
awk 'BEGIN {
DQ = "\042" # double quote (ASCII octal 42)
filename = "path to file with spaces"
"file " DQ filename DQ | getline
print
}'
or, assuming this is part of a larger awk
program,
BEGIN {
SQ = "\047"
DQ = "\042"
}
BEGIN {
name = "filename with spaces"
cmd = sprintf("file %s%s%s", DQ, name, DQ)
cmd | getline
close(cmd)
print
}
That is, close the command when done with it to save on open file handles. Set up convenience "constants" in a separate BEGIN
block (these blocks are executed in order). Create the command using sprintf
into a separate variable. (Most of these things are obviously for longer or more complicated awk
programs that needs to present a readable structure to be maintainable; one could also imagine writing a dquote()
and squote()
function that quotes strings)
The left hand side of the "pipe" will evaluate to the literal string
file "path to file with spaces"
Basically, using cmd | getline
makes awk
call sh -c
with a single argument, which is the string cmd
. That string therefore must be properly quoted for executing with sh -c
.
The technical details are found in POSIX standard:
expression | getline [var]
Read a record of input from a stream piped from the output of a command. The stream shall be created if no stream is currently open with the value of expression
as its command name. The stream created shall be equivalent to one created by a call to the popen()
function with the value of expression as the command argument and a value of r
as the mode
argument. As long as the stream remains open, subsequent calls in which expression
evaluates to the same string value shall read subsequent records from the stream. The stream shall remain open until the close
function is called with an expression that evaluates to the same string value. At that time, the stream shall be closed as if by a call to the pclose()
function. If var
is omitted, $0
and NF
shall be set; otherwise, var
shall be set and, if appropriate, it shall be considered a numeric string (see Expressions in awk).
The popen()
function referred to here is the C popen()
library function. This arranges for he given string to be executed by sh -c
.
You'll have exactly the same issue with system()
if executing a command using a filename with spaces, but in that case the C library's system()
function is called, which also calls sh -c
in a similar way as popen()
(but with different plumbing of I/O streams).
So, no amount of setting IFS
to anything would help if sh -c
was invoked with the single argument
file path to file with spaces
$var
or$(cmd)
(if outside doublequotes) or executingread v1 v2
– dave_thompson_085 Apr 25 '20 at 04:30