`I have a script where I am attempting to read from a manifest file, translate DOS paths in that manifest to UNIX paths, and then operate on those files. Here is a snippet of code that I am trying to debug:
while read line
do
srcdir=$(printf '%s' "$line" | awk -F \\ -v OFS=/ '{ gsub(/\r|^[ \t]+|[ \t]+$/, "") } !NF { next } /^\\\\/ { sub(/^.*\\prj\\/, "\\prj\\") } { $1 = $1 } 1')
done < manifest.txt
My input file looks like this:
$ cat manifest.txt
\\server\mount\directory
When I debug my little shell snippet, I get the following:
+ read line
++ printf %s '\servermountdirectory
'
++ awk -F '\' -v OFS=/ '{ gsub(/\r|^[ \t]+|[ \t]+$/, "") } !NF { next } /^\\\\/ { sub(/^.*\\prj\\/, "\\prj\\") } { $1 = $1 } 1'
+ srcdir=\servermountdirectory
So... Either at read or at printf, the \
characters are being interpreted as escape characters -- how do I work around that?
Note... I know I could just run the while
loop in awk... the thing is that in my real program, I have other things inside that while
loop that need to be done with "$srcdir"
-- and for this, sh is the right tool... So I really need a solution in sh.
From posix read:
By default, unless the -r option is specified, < backslash> shall act as an escape character. An unescaped < backslash> shall preserve the literal value of the following character, with the exception of a < newline>. If a < newline> follows the < backslash>, the read utility shall interpret this as line continuation. The < backslash> and < newline> shall be removed before splitting the input into fields. All other unescaped < backslash> characters shall be removed after splitting the input into fields.
and:
-r
Do not treat a character in any special way. Consider each to be part of the input line.
Just:
while read -r line; do
Also remember that without IFS=
this will not preserve trailing and leading whitespaces.
Remember to always do read -r
. Here is a good read: bashfaq How can I read a file (data stream, variable) line-by-line (and/or field-by-field)?.
Also remember that reading file line by line is very inefficient in bash. It's way better to process the whole file using commands, tools, streams and pipes. If you have to read the file line by line, let the "preprocessing" stage parse the whole file, then read it line by line:
awk .... manifest.txt |
while read -r srcdir; do
echo "$srcdir"
done
or with command redirection, if you need the loop to run in the same shell:
while read -r srcdir; do
echo "$srcdir"
done < <(awk ... manifest.txt)