Как использовать sed и cut для поиска и замены значения в определенной позиции строки в файле

#shell #unix #sed #cut

#оболочка #unix #sed #вырезать

Вопрос:

У меня есть случай, когда я должен заменить число 1 на число 3 в 10-м расположении различных строк в сохраненном текстовом файле. Я не могу найти способ сделать это. Ниже приведен пример файла и кода.

Пример файла:

 $ cat testdata.txt
1  43515 8 1 victor    Samuel    20190112
3215736  4 6 Michael   pristine  20180923
1  56261 1 1 John      Carter    19880712
  
 #!/bin/sh
filename=testdata.txt
echo "reading number of line"
nol=$(cat $filename | wc -l)
flag[$nol]=''
echo "reading content of file"
for i in (1..$nol)
do
flag=($cut -c10-11 $filename)
if($flag==1)
sed 's/1/3/2'
fi
done
  

Но это не работает.

Пожалуйста, помогите решить эту проблему.

Обновлено:

Пример вывода:

 1  43515 8 1 victor    Samuel    20190112
3215736  4 6 Michael   pristine  20180923
1  56261 3 1 John      Carter    19880712
  

Комментарии:

1. Пожалуйста, взгляните: shellcheck.net

2. Вам также необходимо предоставить пример вывода. Ваше описание проблемы довольно краткое и немного неясное

3. Это не похоже на подходящие инструменты для работы. Как насчет использования языка программирования, более ориентированного на обработку строк, такого как awk, perl или python? Было бы довольно просто сделать это с помощью одного из них, и в большинстве систем Linux все они предустановлены.

4. Причина использования сценария оболочки заключается в том, что я использую pig для хранения сложных данных во внешней таблице hive, а затем генерирую файлы оболочкой после некоторых манипуляций.

Ответ №1:

попробуйте это

 sed "s/^(.{8}) 1 (.*)$/1 3 2/g" testdata.txt > new_testdata.txt
  

Если sed поддерживает опцию -i, вы также можете редактировать на месте.

 sed -i "s/^(.{8}) 1 (.*)$/1 3 2/g" testdata.txt
  

вывод

 1  43515 8 1 victor     Samuel 20190112
3215736 4 6 Michael pristine 20180923
1  56261 3 1 John      Carter    19880712
  

объяснение

 s              # substitute
/^(           # from start of line, save into arg1
.{8}         # the first 8 characters
) 1 (        # search pattern ' 1 '
.*             # save the rest into arg2
)$/           # to the end of the line
1 3 2        # output: arg1 3 arg2
/g             # global on whole line
  

Комментарии:

1. Некоторые небольшие улучшения: Вам не нужен глобальный флаг. Сопоставление подстроки после `1` устарело. Когда sed поддерживает это. флаг -r помогает избежать обратной косой черты: sed -ri 's/^(.{8}) 1 /1 3 /' testdata.txt

2. Спасибо @UtLax, это очень помогло. Объяснение, данное вами, очень помогло понять выражение.