Удалить n-ю строку (если считать снизу)

Похоже, вашу логику можно свести к:

grep -om1 "$1" < "$2" ||
echo 'Not available.'

... в любом случае при условии, что GNU grep . Хотя, если бы это был я, я бы отбросил echo или, по крайней мере, сделал бы ...

! echo 'Not available.' >&2

... вместо этого.

7
18.04.2019, 12:17
7 ответов

Чтобы удалить, например, 4-ю строку снизу, используйтеsed:

tac input | sed '4d' | tac

Чтобы перезаписать входной файл:

tmpfile=$(mktemp)
tac input | sed '4d' | tac > "$tmpfile" && mv "$tmpfile" input
17
27.01.2020, 20:13

если $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...

3
27.01.2020, 20:13

sedне может вычислить n-ю строку снизу сам по себе, поэтому нам нужно сделать это раньше, например. используяawk:

Удалить 4-ю строку снизу:

delrow=$(awk -v n=4 'END { print NR-n+1 }' file)
sed -i "${delrow}d" file
0
27.01.2020, 20:13

Одна -строка, в -место решения:

С 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.

0
27.01.2020, 20:13

Это помечено sedи awk, но в вопросе не упоминается, что это необходимо для решения. Вот фильтр Perl, который удаляет 4-ю -из -последней строки и выводит результат. Вывод может быть записан в файл tmp, а затем использован для замены оригинала.

 perl -e '@L = <STDIN>; splice(@L,-4,1); print @L'./lines.txt
2
27.01.2020, 20:13

Для этого можно комбинировать headи tail.

Если необходимо удалить n-ю строку снизу

  1. headчитает из стандартного ввода и передает отчеты в стандартный вывод всего -n строк сверху
  2. tailчитает и сообщает на стандартный вывод нижние n -1 строк из стандартного ввода.
  3. Таким образом, в целом строки передаются в стандартный вывод по порядку, причем *n-я `строка с конца пропускается

Это решение зависит от headоставления смещения файла описания открытого файла сразу после последней строки, о которой сообщается -Я полагаю, что GNU headдействительно делает это, когда стандартный ввод перенаправляется из файла

n=200; tmpfile=$(mktemp) && { head -n -$n; tail -n -$((n-1)); }<file >"$tmpfile" \
    && mv -- "$tmpfile" file
1
27.01.2020, 20:13

Ни стандарт 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.

1
27.01.2020, 20:13

Теги

Похожие вопросы