sed заменить текст между запятыми - PullRequest
0 голосов
/ 24 октября 2019

У меня есть CSV-файлы, которые должны быть изменены f -> 0 и t -> 1 только между запятыми для каждого CSV, если он совпадает. С:

,t,t,f,f,a,t,f,t,f,f,t,f,
tftf

до:

,1,1,0,0,a,1,0,1,0,0,1,0,
tftf

Работает таким образом, но хотите узнать лучший способ, который мог бы сократить время замены, потребляют

for i in 1 2 3 4 5 6
do
  echo "converting tables for mariaDB"
  find ./ -type f -name "*.csv" -print0 | xargs -0 sed -i 's/\,t\,/\,1\,/g'
  find ./ -type f -name "*.csv" -print0 | xargs -0 sed -i 's/\,f\,/\,0\,/g'
  echo "$i time(s) changed "
done

I, кромеодна команда изменит строку

Ответы [ 2 ]

1 голос
/ 24 октября 2019

Основная проблема, в данном случае, заключается в том, что регулярное выражение не допускает перекрытия при разборе его с sed 's/ere/str/g' или awk '{gsub(ere,str,$0)}'. Этот комментарий хорошо объясняет, как вы можете обойти это в sed с помощью команды t<label>, что означает: если произошло изменение в пространстве шаблона, перейдите к Комментарий показывает общий способ сделать это. Альтернативой этому правилу awk будет:

$ awk '{while(match($0,ere)) gsub(ere,str)}'

Альтернативное решение sed в случае примера OP может использовать следующую идею:

  1. дублировать все запятые. Так как мы ищем строки вида ", t", это дублирование позволяет избежать дублирования, используя s.
  2. , поскольку перекрытие невозможно, замените все ", f," на ", 0," иall ", t," with ", 1,".
  3. Теперь мы можем снова вернуть все дублированные запятые. Поскольку перекрытие не допускается, последовательности, подобные ,,,,, будут преобразованы в ,,, а не ,

В POSIX sed это выглядит следующим образом:

$ sed -e 's/,/,,/g' -e 's/,f,/,0,/g' \
      -e 's/,t,/,1,/g' -e 's/,,/,/g' file > file.tmp
$ mv file.tmp file

СGNU SED мы можем сделать это за один раз:

$ sed -i 's/,/,,/g;s/,f,/,0,/g;s/,t,/,1,/g;s/,,/,/g' file

С awk это будет выглядеть так:

$ awk 'BEGIN{FS=",";OFS=FS FS}
       {$1=$1;gsub(/,f,/,",0,");gsub(/,t,/,",1,");gsub(OFS,FS)}1' file > file.tmp
$ mv file.tmp file
1 голос
/ 24 октября 2019

Не могли бы вы попробовать следующее. Хотя это не идеальное решение, но было бы проще использовать его, если у вас нет последней версии gawk, где присутствует опция -inplace.

for file in *.csv
  awk '{gsub(/,t,/,",1,");gsub(/,f,/,",0,");gsub(/,t,/,",1,");gsub(/,f,/,",0,")} 1' "$file" > temp && mv temp"$file"
done

ИЛИ

for file in *.csv
    awk -v t_val="1" -v f_val="0" 'BEGIN{FS=OFS=","}{for(i=2;i<NF;i++){$i=($i=="t"?t_val:$i=="f"?f_val:$i)}} 1' "$file" > temp && mv temp "$file"
done


2-е решение: Использование последней версии gawk, в которой мы можем сохранить изменения в самом файле Input_file.

gawk -i inplace '{gsub(/,t,/,",1,");gsub(/,f,/,",0,");gsub(/,t,/,",1,");gsub(/,f,/,",0,")} 1' *.csv

ИЛИ

gawk -i inplace -v t_val="1" -v f_val="0" 'BEGIN{FS=OFS=","}{for(i=2;i<NF;i++){$i=($i=="t"?t_val:$i=="f"?f_val:$i)}} 1' Input_file
...