Как я могу заменить строки в, скажем, «последних 10 строках» нескольких файлов?
У меня есть около 100 файлов с одинаковым расширением «.txt», и я хотел бы заменить строку «GLN» 'на' LOO 'в последних 10 строках каждого файла. Как мне это сделать? Я знаю, как сделать это для одного файла, но не для нескольких файлов. Когда я использую эту команду:
for i in `head -3 *.txt | awk '{print $4}'`
do
sed -i 's/GLN/LOO/g' *.txt
done
Она заменяет GLN везде, где встречается в файлах, а не только в последних 10 строках. Пожалуйста, что я делаю не так?
Неясно, что head -3 *.txt | awk '{print $4}'
возвращает здесь, поскольку вы не показали нам образец вашего файла(ов), однако sed -i 's/GLN/LOO/g' *. txt
заменит все экземпляры GLN в всех строках в всех файлах, соответствующих *.txt
, при условии, что цикл выполнится хотя бы один раз.
AFAIK не существует прямого способа обратиться к последним n строкам файла в sed - поэтому, чтобы использовать это, вам нужно вычислить смещение извне, используя wc -l
и арифметику shell, например:
for f in *.txt; do
start=$(( $(wc -l <"$f") - 9 ))
sed "$start"',$s/GLN/LOO/g' "$f"
done
(я удалил -i
, чтобы вывод шел в терминал, для тестирования). Вы можете использовать что-то вроде awk 'END{print NR-9}' "$f"
вместо $(( $(wc -l <"$f") - 9 ))
для получения начального смещения, если вы собираетесь использовать awk.
В качестве альтернативы вы можете использовать tac
, чтобы инвертировать файл и сделать замены в первых n строках, а затем tac
результат - хотя это усложняет замену на месте.
В этой ситуации я бы, вероятно, обратился к ed
или ex
, которые поддерживают числовые смещения адреса ex. тестирование с выводом в терминал:
for f in *.txt; do
printf '%s\n' '$-9,$s/GLN/LOO/g' ',p' | ed -s "$f"
done
Как только вы убедитесь, что все идет правильно, измените ,p
на wq
на wзапишите результат в файл (эквивалент команды sed -i
).