Похоже, вашу логику можно свести к:
grep -om1 "$1" < "$2" ||
echo 'Not available.'
... в любом случае при условии, что GNU grep
. Хотя, если бы это был я, я бы отбросил echo
или, по крайней мере, сделал бы ...
! echo 'Not available.' >&2
... вместо этого.
Чтобы удалить, например, 4-ю строку снизу, используйтеsed
:
tac input | sed '4d' | tac
Чтобы перезаписать входной файл:
tmpfile=$(mktemp)
tac input | sed '4d' | tac > "$tmpfile" && mv "$tmpfile" input
если $n
содержит номер удаляемой строки
для удаления одной строки используйте
printf "\$-%d+1,\$-%d+1d\nwq\n" $n $n| ed -s file
удалить n последних строк
printf "\$-%d,\$d\nwq\n" $n | ed -s file
где
\$%d,\$d
приказано удалить n последних строк (printf вставит n)wq
написать и выйти -s
в ed -s
будет хранить молчание.
обратите внимание, что не предусмотрена проверка наличия достаточного количества строк для удаления.
к сожалению, диапазон от конца не может быть указан в sed
...
sed
не может вычислить n-ю строку снизу сам по себе, поэтому нам нужно сделать это раньше, например. используяawk
:
Удалить 4-ю строку снизу:
delrow=$(awk -v n=4 'END { print NR-n+1 }' file)
sed -i "${delrow}d" file
Одна -строка, в -место решения:
С gawk
это удалит 42-ю строку снизу:
gawk -i inplace 'i==0 {if(FNR>t){t=FNR}else{i=1}} i==1 && FNR!=t-42 {print}' input input
42 можно заменить любым числом. Если используется 0, то последняя строка удаляется.
Обратите внимание, что файл input
указан дважды. Это вызывает две итерации файла с gawk. В первой итерации(i==0
)устанавливается общее количество строк (t
). Во второй итерации n-я строка с конца не выводится.
Файл изменяется на месте с помощью параметра -i
.
Это помечено sed
и awk
, но в вопросе не упоминается, что это необходимо для решения. Вот фильтр Perl, который удаляет 4-ю -из -последней строки и выводит результат. Вывод может быть записан в файл tmp, а затем использован для замены оригинала.
perl -e '@L = <STDIN>; splice(@L,-4,1); print @L'./lines.txt
Для этого можно комбинировать head
и tail
.
Если необходимо удалить n-ю строку снизу
head
читает из стандартного ввода и передает отчеты в стандартный вывод всего -n строк сверху tail
читает и сообщает на стандартный вывод нижние n -1 строк из стандартного ввода. Это решение зависит от head
оставления смещения файла описания открытого файла сразу после последней строки, о которой сообщается -Я полагаю, что GNU head
действительно делает это, когда стандартный ввод перенаправляется из файла
n=200; tmpfile=$(mktemp) && { head -n -$n; tail -n -$((n-1)); }<file >"$tmpfile" \
&& mv -- "$tmpfile" file
Ни стандарт sed
, ни awk
не поддерживают редактирование на месте.
Для этого лучше использовать ed(1)
илиex(1)
:
printf '$-%dd\nw\n' 1 | ed -s your_file
Или здесь -документ
ed -s <<'EOT' your_file
$-1d
w
EOT
С расширенными оболочками, такими как bash
, zsh
или ksh93
, вы можете использовать синтаксис $'...'
и здесь -строки:
ed -s <<<$'$-1d\nw' your_file
Обратите внимание, что адрес $
означает последнюю строку файла; поэтому индекс 1 есть 0 -на основе ; для 1-й строки от конца замените 1 на 0 ($-0
), для 3-й на 2($-2
)и т. д.
Помещение в функцию:
del_nth_line_from_end(){ printf '$-%dd\nw\n' "$(($2-1))" | ed -s "$1"; }
Вместо ed -s
везде можно использовать ex -s
или vim -es
.