Если я правильно понял ваше требование, вы можете использовать следующую команду awk
:
awk -v samples="$(($(grep -c. input)-1))" 'NR == 1 { $1=samples }1' input
samples
будет установлено на количество строк в файле input
минус одна (, так как вы не считаете строку заголовка ).
awk
изменит первый столбец первой строки на новый номер образца и напечатает все.
$ cat input
5 10
sample_1 gaatatccga
sample_2 gaatatccga
sample_3 gaatatccga
$ awk -v samples="$(($(grep -c. input)-1))" 'NR == 1 { $1=samples }1' input
3 10
sample_1 gaatatccga
sample_2 gaatatccga
sample_3 gaatatccga
С помощью GNU awk вы можете использовать флаг -i
для изменения файлов на месте, но я бы предпочел создать второй набор измененных файлов, чтобы гарантировать, что были внесены правильные изменения.
Что-то вроде:
for file in *.phy; do
awk -v samples="$(($(grep -c. "$file")-1))" 'NR == 1 { $1=samples }1' "$file" > "${file}.new"
done
Другим вариантом было бы использование ed
(, конечно!):
for f in input*
do
printf '1s/[[:digit:]][[:digit:]]*/%d\nw\nq' $(( $(wc -l < "$f") - 1 )) | ed -s "$f"
done
Это перебирает файлы (с именами, напримерinput
-something )и отправляет простой скрипт ed -вed
:
1
, найдите и замените(s//
)одну или несколько цифр в начале строки другим числом --, это число замены является результатом вычисления длины строки ввода минус один w
запишите файл и q
выход В Vim запустите:
:execute '1s/^[0-9]\+/'. (line('$')-1). '/'
(Спасибо также этому ответу за то, что он указал мне правильное направление.)
Вы также можете сделать это в цикле, например. используя :bufdo
или просто цикл оболочки for
.