«У меня есть сценарий, в котором я пытаюсь прочитать файл манифеста, преобразовать пути DOS в этом манифесте в пути UNIX, а затем работать с этими файлами. Вот фрагмент кода, который я пытаюсь отладить:
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
Мой входной файл выглядит так:
$ cat manifest.txt
\\server\mount\directory
Когда я отлаживаю свой небольшой фрагмент оболочки, я получаю следующее:
+ read line
++ printf %s '\servermountdirectory
'
++ awk -F '\' -v OFS=/ '{ gsub(/\r|^[ \t]+|[ \t]+$/, "") } !NF { next } /^\\\/ { sub(/^.*\\prj\/, "\\prj\\") } { $1 = $1 } 1'
+ srcdir=\servermountdirectory
Итак... Либо при чтении, либо при печати символы \ интерпретируются как escape-символы - как мне обойти это?
Примечание... я знаю, что могу просто запустить цикл while в аук... дело в том, что в моей реальной программе у меня есть другие вещи внутри этого цикла while, которые нужно выполнить с помощью "$srcdir" -- и для этого ш правильный инструмент... Так что мне действительно нужно решение в ш.





Из posix читать:
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.
а также:
-r
Do not treat a character in any special way. Consider each to be part of the input line.
Только что:
while read -r line; do
Также помните, что без IFS= это не сохранит конечные и ведущие пробелы.
Не забывайте всегда делать read -r. Вот хорошее чтение: bashfaq Как прочитать файл (поток данных, переменную) построчно (и/или по полям)?.
Также помните, что чтение файла построчно в bash очень неэффективно. Гораздо лучше обрабатывать весь файл с помощью команд, инструментов, потоков и каналов. Если вам нужно прочитать файл построчно, пусть этап «предварительной обработки» проанализирует весь файл, а затем прочитает его построчно:
awk .... manifest.txt |
while read -r srcdir; do
echo "$srcdir"
done
или с перенаправлением команд, если вам нужно, чтобы цикл выполнялся в той же оболочке:
while read -r srcdir; do
echo "$srcdir"
done < <(awk ... manifest.txt)
Я полностью с вами согласен, но действительно ли нам нужно читать файл и печатать каждую строку в awk перед обработкой? это как делать работу в два раза больше... в любом случае +1
Спасибо, Камиль - отлично!
Я думаю, что это не совсем [дубликат] -- потому что в данном случае я не знал, было ли это
printfили читал, что это была проблема, и не мог понять, как определить разницу... но решать вам. ;) Я действительно ценю ответы здесь. Камил был точен, и Аллан тоже мог добавить несколько хороших вещей.