Для правильной обработки разделителей в кавычках вам следует рассмотреть возможность использования специального анализатора 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
Если у вас есть доступ к vim
, вы можете использовать :
for file in ./*
do
if [ -f "${file}" ]
then
vim -c '$d' -c "wq" "${file}"
fi
done
Использование 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
) или последнюю (правильно разделенную) строку и эти дополнительные байты.
Более переносимый подход:
for f in ./*
do
test -f "$f" && ed -s "$f" <<\IN
d
w
q
IN
done
Я не думаю, что это требует каких-либо объяснений ... кроме, может быть, того, что в этом случае d
совпадает с $ d
, поскольку ed
по умолчанию выбирает последнюю строку.
При этом не будет выполняться рекурсивный поиск и не будут обрабатываться скрытые файлы (также известные как файлы точек).
Если вы хотите редактировать и их, см. Как сопоставить * со скрытыми файлами внутри каталога
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 {} +
Также смотрите:
Во всех других ответах есть проблемы, если каталог содержит что-то, кроме обычного файла, или файл с пробелами / новой строкой в имени файла. Вот кое-что, что работает независимо:
find "$dir" -type f -exec sed -i '$d' '{}' '+'
найти "$ dir" -тип f
: найти файлы в каталоге $ dir
-тип f
, которые являются обычными файлами; - exec
выполнить команду для каждого найденного файла sed -i
: отредактировать файлы на месте; '$ d'
: удалить ( d
) последний ( $
) строка. '+'
: указывает find продолжать добавлять аргументы в sed
(немного более эффективно, чем запуск команды для каждого файла отдельно, благодаря @zwol). Если вы не хотите спускаться в подкаталоги, вы можете добавить аргумент -maxdepth 1
в find
.
Вы можете использовать этот красивый oneliner, если у вас есть GNU sed
.
sed -i '$ d' ./*
Удаляет последнюю строку каждого не скрытого файла в текущем каталоге. Переключатель -i
для GNU sed
означает работу на месте, а '$ d'
дает команду sed
удалить последнюю строку ( $
означает последний и d
означает удаление).