Почему awk не игнорирует пробел в качестве разделителя?

У меня был подобный случай. Обходной путь :, если у вас есть /etc/init.d/mysql, удалите mariadb.service, mysqld.service, mysql.service.

systemctl daemon-reload
/etc/init.d/mysql start
6
08.04.2020, 20:51
4 ответа

Причина, по которой ваш awk не дает ожидаемых результатов, связана с тем, как вы перебираете файл. Когда вы выполняете итерацию с использованием for i in $(cat file), вы выполняете итерацию по словам (, разделенным IFS ), а не по строкам. Чтобы прочитать файл построчно, используйтеwhile read:

while read -r line; do
   ...
done < file

Для дальнейшего чтения см. следующие часто задаваемые вопросы по bash:Как я могу прочитать файл (поток данных, переменную )строку -по -строку (и/или поле -полем -)?

2
28.04.2021, 23:18

Если я вас правильно понял, вы можете использовать цикл while и раскрытие переменных

while IFS= read -r line; do 
  id="${line%;*}"
  name="${line#*;}"
  cp sample.xml output/input.tmp
  sed -i -e "s/xxx/$id/g" output/input.tmp
  sed -i -e "s/yyy/$name/g" output/input.tmp
  mv output/input.tmp output/"$name".xml
done < file

Как предложил @steeldriver , вот (более элегантный )вариант:

while IFS=';' read -r id name; do 
  cp sample.xml output/input.tmp
  sed -i -e "s/xxx/$id/g" output/input.tmp
  sed -i -e "s/yyy/$name/g" output/input.tmp
  mv output/input.tmp output/"$name".xml
done < file
7
28.04.2021, 23:18

Цитирую !!. Цитата в этой строке отсутствует:

mv output/input.tmp output/$name.xml

Так и должно быть:

mv output/input.tmp output/"$name".xml

, чтобы избежать проблем с именем файла с пробелами.

Кроме того, расширение $(cat list)разделяется (и заполняет )оболочкой, которая также разрывается в пробелах.

Может быть, вы можете перейти на этот скрипт:

#!/bin/bash -x
rm -f output/*

inputfile=output/input.tmp

while read -r line
do
    id=${line%%;*}
    name=${line##*;}

    cp sample.xml "$inputfile"
    sed -i -e "s/xxx/$id/g" "$inputfile"
    sed -i -e "s/yyy/$name/g" "$inputfile"
    mv "$inputfile"  output/"$name".xml; echo

done <list
4
28.04.2021, 23:18

В качестве альтернативного подхода вы можете выполнить эту работу с помощью awk в 1 процессе, а не в 4 для каждой строки. Это, скорее всего, будет полезно, если в списке много строк, но файл sample.xml мал.

awk -F';' 'FNR==NR{x=x $0 RS; next} 
{t=x; gsub(/xxx/,$1,t); gsub(/yyy/,$2,t); f="output/"$2".xml"; printf "%s",t >f; close(f)}
' sample.xml list
# shown with unnecessary linebreaks for clarity, but you can put it all on one line

Если в списке есть окончания строки CRLF (, также известные как формат DOS или Windows ), как указано в вашем вопросе, и вы не можете (легко )или не хотите удалять их в первую очередь, awk может справиться с этим тоже; сразу после второго {вставьтеsub(/\r$/,"",$0);(или $2, если хотите ).

perl также может делать это (perl может делать почти все, что может делать awk )но немного более подробно, и хотя perl общедоступен, он не соответствует POSIX, как awk.

0
28.04.2021, 23:18

Теги

Похожие вопросы