Как удалить последнюю строку всех файлов из каталога?

Для правильной обработки разделителей в кавычках вам следует рассмотреть возможность использования специального анализатора CSV - например, одного из модуля Perl Text :: CSV. Например,

paste -d, input.csv column.csv | perl -MText::CSV -ne '
  BEGIN {$csv = Text::CSV->new()}
  if ($csv->parse($_)) {
    @a = $csv->fields();
    splice(@a, 3, 1);
    print join(",", @a) . "\n";
  }'
1,2,3,9,12,30
1,2,3,9,12,36
1,2,3,9,12,90
17
01.02.2017, 14:03
6 ответов

Если у вас есть доступ к vim , вы можете использовать :

for file in ./*
do
  if [ -f "${file}" ]
  then
    vim -c '$d' -c "wq" "${file}"
  fi
done
5
27.01.2020, 19:46

Использование GNU sed -i '$ d' означает чтение полного файла и создание его копии без последней строки, в то время как было бы намного эффективнее просто обрезать файл на месте (по крайней мере, для больших файлов).

С помощью GNU truncate вы можете:

for file in ./*; do
  [ -f "$file" ] &&
    length=$(tail -n 1 "$file" | wc -c) &&
    [ "$length" -gt 0 ] &&
    truncate -s "-$length" "$file"
done

Если файлы относительно малы, это, вероятно, будет менее эффективным, поскольку он запускает несколько команд для каждого файла.

Обратите внимание, что для файлов, которые содержат дополнительные байты после последнего символа новой строки (после последней строки) или, другими словами, если у них есть последняя строка без разделителей , то в зависимости от хвоста Реализация , tail -n 1 вернет только эти дополнительные байты (например, GNU tail ) или последнюю (правильно разделенную) строку и эти дополнительные байты.

9
27.01.2020, 19:46

Более переносимый подход:

for f in ./*
do
test -f "$f" && ed -s "$f" <<\IN
d
w
q
IN
done

Я не думаю, что это требует каких-либо объяснений ... кроме, может быть, того, что в этом случае d совпадает с $ d , поскольку ed по умолчанию выбирает последнюю строку.
При этом не будет выполняться рекурсивный поиск и не будут обрабатываться скрытые файлы (также известные как файлы точек).
Если вы хотите редактировать и их, см. Как сопоставить * со скрытыми файлами внутри каталога

6
27.01.2020, 19:46

POSIX-совместимый однострочный поиск всех файлов рекурсивно, начиная с текущего каталога, включая dot-файлы:

find . -type f -exec sh -c 'for f; do printf "\$d\nx\n" | ex "$f"; done' sh {} +

Только для .txt файлов, нерекурсивно:

find . -path '*/*/*' -prune -o -type f -name '*.txt' -exec sh -c 'for f; do printf "\$d\nx\n" | ex "$f"; done' sh {} +

Также смотрите:

3
27.01.2020, 19:46

Во всех других ответах есть проблемы, если каталог содержит что-то, кроме обычного файла, или файл с пробелами / новой строкой в ​​имени файла. Вот кое-что, что работает независимо:

find "$dir" -type f -exec sed -i '$d' '{}' '+'
  • найти "$ dir" -тип f : найти файлы в каталоге $ dir
    • -тип f , которые являются обычными файлами;
    • - exec выполнить команду для каждого найденного файла
    • sed -i : отредактировать файлы на месте;
    • '$ d' : удалить ( d ) последний ( $ ) строка.
    • '+' : указывает find продолжать добавлять аргументы в sed (немного более эффективно, чем запуск команды для каждого файла отдельно, благодаря @zwol).

Если вы не хотите спускаться в подкаталоги, вы можете добавить аргумент -maxdepth 1 в find .

11
27.01.2020, 19:46

Вы можете использовать этот красивый oneliner, если у вас есть GNU sed .

 sed -i '$ d' ./*

Удаляет последнюю строку каждого не скрытого файла в текущем каталоге. Переключатель -i для GNU sed означает работу на месте, а '$ d' дает команду sed удалить последнюю строку ( $ означает последний и d означает удаление).

17
27.01.2020, 19:46

Теги

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