LINUX.ORG.RU

bash посчитать количество строк в файле по заданному пути

 , , , ,


0

1

Добрый день. Есть задача: Посчитать количество строк в файлах и записать в файл текущая дата\путь к файлу\количество строк . Причем если текущая дата 1 число то считаем предыдущий месяц (папка 2210), если не 1 то текущий месяц (2211)

Пока написал такой скрипт

#!/bin/bash

#заносим в переменную текущее число месяца

timestamp=$(date +%d)

#если сейчас 1 число то присваиваем переменной предыдущий месяц, иначе текущий

if [[ $timestamp == 1 ]]; then

folder= date -d " - $(date +%d) days" +%y%m

else

folder=$(date +%y%m)

fi

#находим путь до нужных файлов ($folder либо текущий либо предыдущий месяц)

find . ( -name «$folder» ) -exec ls ‘{}’ ;

Но тут возник вопрос - Как теперь посчитать кол-во строк в файлах по этому пути и записать в файл текущая дата\путь к файлу\количество строк



Последнее исправление: krdgroup (всего исправлений: 1)
Ответ на: комментарий от Vsevolod-linuxoid

да, у меня файлы заархивированы поэтому использую

zcat file.gz | wc –l

только как как сюда передать файл из find . ( -name «$folder» ) -exec ls ‘{}’ ;

krdgroup
() автор топика
Ответ на: комментарий от krdgroup

zcat file.gz | wc –l
только как как сюда передать файл из find . ( -name «$folder» ) -exec ls ‘{}’ ;

а на что по вашему заменяются скобки ‘{}’?

-exec bash -c "zcat '{}' | wc -l >> log.file"

но лучше заменить действие -exec на вызов своего скрипта, передавая ему имя файла.

-exec processing-file '{}'
sigurd ★★★★★
()
Последнее исправление: sigurd (всего исправлений: 3)
Ответ на: комментарий от sigurd

А из-за чего он может не записывать количество строк в файлах?

find . ( -name «$folder» ) -exec bash -c «wc -l >> log.txt» ;

В идеале он должен в log.txt записывать кол-во строк из файлов с названием $folder + текущую дату + название родительской папки для $folder

krdgroup
() автор топика
Ответ на: комментарий от krdgroup

man wc

wc ждет имя файла - либо wc -l {}, либо cat {} | wc -l

sigurd ★★★★★
()
Последнее исправление: sigurd (всего исправлений: 2)
Ответ на: комментарий от sigurd

а как файлы из $folder ему передать передать?

find . ( -name «$folder» ) -exec bash -c «zcat ‘$folder’ | wc -l >> log.txt» ;

работает только если в том же каталоге размещать файл, а нужно чтобы все файлы в $folder считал

find . ( -name «$folder» ) -exec bash -c «zcat ‘1.z’ | wc -l >> log.txt» ;

krdgroup
() автор топика
Ответ на: комментарий от sigurd

как этот скрипт изменить чтобы он файлы не в корневом каталоге выводил а брал их из переменной

p= find . ( -name «$folder» );

если так писать

for f in $(ls $p) do echo $f done

все равно из корневого берет

krdgroup
() автор топика
Ответ на: комментарий от krdgroup
for p in $(find /usr/local -type f); do
    echo $p
done

Потому что ls не выводит путь к файлу.

Если делать с ls, то можно дописать путь к файлу самостоятельно в качестве префикса.

А вообще, эффективнее взять книгу по bash или Bash HOWTO, или одно из многочисленных руководств, чем итеративно пытаться сварить кашу из топора, собирая разрозненные советы на каждую строчку на каждом этапе.

emorozov ☆
()
Последнее исправление: emorozov (всего исправлений: 1)
Ответ на: комментарий от krdgroup

p= find . ( -name «$folder» );
если так писать
for f in $(ls $p) do echo $f done
все равно из корневого берет

for+ls вместо find!!!
for f in $(ls $folder) do echo $folder/$f done
выводит все файлы в каталоге folder

ну или правильно find использовать (man find) -
find $folder -type f -exec ls {} \;

sigurd ★★★★★
()
Последнее исправление: sigurd (всего исправлений: 6)
Ответ на: комментарий от sigurd

а как через переменную сделать?

так все работает

folder=./AXE/TELLIN/2211
for f in $(ls $folder) 
do 
	echo $p/$f 
done

а если через переменную путь задаю то не работает, все равно из корневого данные выводит 
p= find ./ -type d -name "$folder"
for f in $(ls $p) 
do 
	echo $p/$f 
done
krdgroup
() автор топика
Ответ на: комментарий от krdgroup

Ты пишешь полную ересь, не понимая синтаксис шелла, что такое в нем переменные, команды, и как их комбинировать.

Для начала надо почитать основы, просто заниматься случайными изменениями «авось заработает» - непродуктивно.

p= find ./ -type d -name "$folder"

Что по-твоему делает эта строка? Я отвечу: это неработающая абракадабра, которую ещё кое-как может понять человек, но не компьютер.

Во-первых, в shell не должно быть пробелов между знаком = и значением. Во-вторых, чтобы подставить вывод команды, надо использовать обратные кавычки или $().

Во-вторых, почему бы сразу не подставить find в цикл, и не получить сразу имена вместе с полным путем, как уже не раз было подсказано?..

emorozov ☆
()
Последнее исправление: emorozov (всего исправлений: 1)

Почему не во всех файлах кол-во строк считает?

#!/bin/bash
#заносим в переменную текущее число месяца
timestamp=$(date +%d) 
#если сейчас 1 число то присваиваем переменной предыдущий месяц, иначе текущий 
if [[ $timestamp == 01 ]]; then
	folder=$(date -d " - $(date +%d) days" +%y%m)
else
	folder=$(date +%y%m)
fi
#находим путь к файлам
path=$(find ./ -type d -name "$folder")
#находим файлы и считааем кол-во записей
for file in $path/*
do
	wc -l $file
done

выдает результат

0 ./AXE/CNA5/LBN/2211
16 ./AXE/TELLIN/2211/1.txt

Хотя по пути ./AXE/CNA5/LBN/2211 тоже лежит файл 2.txt с двумя записями. Причем если в 3-ю директорию размещаю файл тоже только в одной считает

krdgroup
() автор топика
Ответ на: комментарий от krdgroup

Потому что как пишутся скрипты и программы: сначала изучаешь основы языка (shell - это тоже язык программирования), учишься на простых примерах. Затем ставишь задачу, анализируешь, декомпозируешь, и пишешь с учётом полученных знаний.

Ты же просто комбинируешь ошмётки где-то увиденных команд, переставляешь аргументы, без реального понимания, что они делают.

Например, ты понимаешь, что после path=$(find...) у тебя в $path будет лежать несколько путей?

Когда ты дальше пишешь for file in $path/*, что по-твоему происходит с учётом того, что в $path несколько путей?..

Пойми, нельзя научиться писать правильно, безошибочно действуя методом проб и ошибок, бессистемно.

emorozov ☆
()
Последнее исправление: emorozov (всего исправлений: 2)
Ответ на: комментарий от krdgroup

Выше уже объяснили, что ты не понимаешь, что пишешь. Даже не так, ты логику не понимаешь, а уже потом скриптинг. Начни с логики программы без языков, просто опиши по пунктам, что должно быть за чем. Потом почитай основы скриптинга и переложи логику на баш скрипт. И пиши названия переменных так, чтобы они соответствовали содержанию, это тоже помогает разбираться. timestamp у тебя на деле совсем не он, а просто текущий день. Тоже касается folder, path. Итерировать найденное через переменную file тоже не очень, т.к. file - отдельная программа (man file).

Entmatix ★
()
Ответ на: комментарий от Entmatix

Описать логику программы - это более подробно описать как какая команда будет действовать и что выполнять а не так как я в комментариях указал -

#заносим в переменную текущее число месяца

#если сейчас 1 число то присваиваем переменной предыдущий месяц, иначе текущий

#находим путь к файлам

#находим файлы и считаем кол-во записей

krdgroup
() автор топика
Ответ на: комментарий от krdgroup

В твоём скрипте, чтобы понять, почему он работает неправильно, достаточно разобраться в том, как работает команда for, что в ней происходит. Ну и что такое символ * и как он работает в shell.

Просто словами попробуй проговорить или записать: «берётся … и подставляется в переменную …»

Сразу же станет понятно, в чём дело. Наверное.

emorozov ☆
()
Последнее исправление: emorozov (всего исправлений: 1)
Ответ на: комментарий от Entmatix

а как тогда описать по пунктам, что должно быть за чем чтобы это несло конкретику и чтобы потом это на баш скрипт перенести?

krdgroup
() автор топика
Ответ на: комментарий от krdgroup
# Получаем текущий день в формате числа
todays_day="$(date +%d)"

# Узнаем, нужный номер месяца в формате цифры для дальнейшего поиска пути. Для этого проверяем, является ли текущий день первым днем месяца.Сравниваем $todays_day с единицей.

# Если переменная равна единице, берем предыдущий месяц в виде цифры (в команду date передаем аргумент --date='1 day ago', чтобы получить дату предыдущего дня (последнего дня предыдущего месяца) и извлекаем из даты только месяц - %m.
if ((todays_day==1)); then
  month="$(date --date='1 day ago' +%m)"
else

  # Если не равна единице, то берем значение текущего месяца в виде цифры.
  month="$(date +%m)"
fi

И т.д.

Entmatix ★
()

Разобрался с циклом, вот код

if ((todays_day==1)); then
  month="$(date --date='1 day ago' +%y%m)"
else
  month="$(date +%y%m)"
fi
for file in $(find ./ -type d -name "$month")
do
echo "Количество записей $(find $file -type f -name "*.z" | xargs zcat | wc -l)"	 
done

Только сейчас если в файле в конце последней записи нет символа перевода строки (Enter) он ее не считает. Это получается \n куда то в find надо поставить как параметр ? $(find $file -type f -name "*.z" | xargs zcat | wc -l)

krdgroup
() автор топика
Ответ на: комментарий от skinner

Прошу прощения за оффтоп, скажите, как с вами можно связаться?

Я конечно польщен, что вы решили зарегистрироваться на LOR только для того, чтобы связаться со мной. Но похоже, вы путаете LOR со службой знакомств!

sigurd ★★★★★
()
Ответ на: комментарий от sigurd

Хотелось бы познакомиться на тему подключения 2к монитора с единственным dvi разъёмом к видеокарте без dvi разъёма. Соответствующая тема на этом форуме закрыта, но там я нашёл ваши комментарии что это вам удалось. Если не сложно напишите пожалуйста в вк или телегу, id и там и там - skinnernsk Буду благодарен.

skinner
()
Ответ на: комментарий от skinner

Хотелось бы познакомиться на тему подключения 2к монитора с единственным dvi разъёмом к видеокарте без dvi разъёма.

Никогда такими извращениями не страдал, если только под «видеокартой без dvi разъема» не подразумевается hdmi. Во общем - вы меня с кем то путаете!

sigurd ★★★★★
()
Ответ на: комментарий от sigurd

Я имею в виду ваш пост от (06.04.17 17:16:35 GMT+07:00) где вы писали «Все решается нормальным кабелем! У меня так к DVI подключен 4К монитор (только кабель не DVI-HDMI, а обычный полный DVI-DVI + переходник DVI-Displayport). Правда в 4К он дает только 30Гц, но я использую 2560x1440 (на нем - нормальные 60Гц). Да - на видюхе есть и HDMI разъем и 3 DisplayPort, но нормально при старте компа работает только DVI, остальные начинают работать только после загрузки блоба от NVIDIA. Хорошего кабеля DisplayPort-DisplayPort найти пока не удалось!»

skinner
()
Ответ на: комментарий от krdgroup

Опять переменные совершенно неправильно называются. В file лежит не файл, а название каталога. Тебе ведь не понравится, если в жизни на 10-м троллейбусе, который ходит до твоей школы, будет написано 12-й автобус, верно ведь? Или если в магазине на нарезном батоне будет написано «молоко», и наоборот. Неожиданно будет, сложно разобраться и каждый раз в уме переводить туда-обратно.

Если я правильно понял вопрос, то здесь опять же find не при чём.

Логически подумай: find - ищет файлы, wc - считает строки. Каким образом параметры find могут повлиять на то, как совершенно отдельная утилита wc будет считать строки?

Если надо ещё учитывать есть или нет символ перевода строки в последней строке файла, то проще уже на другом языке скрипт писать, например, на Python…

В shell наверное тоже можно сделать, но не на данном уровне владения им. А до нужного уровня владения тебе ещё надо много прочитать и научиться применять.

Вот тут есть готовые варианты решения, но на английском: https://stackoverflow.com/questions/28038633/wc-l-is-not-counting-last-of-the-file-if-it-does-not-have-end-of-line-character

И еще непонятно: разобрался ли ты, как делать вложенные циклы, или не разобрался, и потому считаешь все строки во всех файлах сразу. Если не разобрался, то ответы со StackOverflow наверное не осилишь.

emorozov ☆
()
Последнее исправление: emorozov (всего исправлений: 2)
Ответ на: комментарий от skinner

Я имею в виду ваш пост от (06.04.17 17:16:35 GMT+07:00)

Вы както странно читаете - я подключил к DVI выходу видеокарты Displayport монитор. Где здесь подключение «монитора с единственным dvi разъёмом к видеокарте без dvi разъёма»?
Тип выхода вашей видеокарты - это большой секрет, который нельзя указать?

sigurd ★★★★★
()
Последнее исправление: sigurd (всего исправлений: 1)
Ответ на: комментарий от sigurd

Вы както странно читаете - я подключил к DVI выходу видеокарты Displayport монитор. Где здесь подключение «монитора с единственным dvi разъёмом к видеокарте без dvi разъёма»? Тип выхода вашей видеокарты - это большой секрет, который нельзя указать?

Главное, что у вас получился кабель dvi-d - displayport пропускающий 2560х1440 60гц. Разъёмы на свежих видеокартах hdmi и displayport, разъём на моём мониторе dvi-d. Я очень надеюсь что вы подскажете что у вас за переходник, потому что действительно, зарегистрировался я здесь только для того что бы попросить вашего совета.

skinner
()
Ответ на: комментарий от skinner

Я очень надеюсь что вы подскажете что у вас за переходник

Попробую поискать дома переходник, сейчас уже этот комп вышел из строя.

sigurd ★★★★★
()
Последнее исправление: sigurd (всего исправлений: 1)
Ответ на: комментарий от sigurd

Попробую поискать дома переходник, сейчас уже этот комп вышел из строя.

Буду вам очень благодарен, т.к. монитор у меня отличный, ips 27 дюймов 2560х1440 но имеет только dvi-d разъём. Уже купил несколько кабелей hdmi - dvi-d, которые на упаковке обещали 2560х1440 60гц, но с любым из них монитор просто не ловит сигнал, остаётся в режиме ожидания. Другой монитор, попроще, запускался на 1080р 60гц с этими кабелями. В магазинах у переходников displayport - dvi-d везде указано что максимальное разрешение 1920х1080 60гц.

skinner
()
Ответ на: комментарий от skinner

Увы, точную модель подсказать не смогу - нет уже ни компа, ни той видеокарты с dvi, ни переходника dvi –> displayport. Единственно, что помню: кабель dvi обязательно должен быть dual link, переходник dvi –> displayport был не дешевый (покупал я его на распродаже примерно за 2-3т.руб.). Причем переходник работает только в одну сторону и вам он точно не подойдет!
Вам нужно смотреть активные переходники displayport –> dvi dual port (single port не дадут более 1920x1080x60), которые дают 4К на 60гц - вот только цена не обрадует!

sigurd ★★★★★
()
Последнее исправление: sigurd (всего исправлений: 1)
Ответ на: комментарий от sigurd

Вам нужно смотреть активные переходники displayport –> dvi dual port (single port не дадут более 1920x1080x60), которые дают 4К на 60гц - вот только цена не обрадует!

Активный переходник, это который имеет плату и запитывается дополнительно от юсб?

skinner
()
Ответ на: комментарий от skinner

Активный переходник, это который имеет плату и запитывается дополнительно от юсб?

Именно так! Пассивные кабели и переходники работают по одному каналу и не могут дать более 1920х1080.

sigurd ★★★★★
()

Делай через

find ... | while read FN ; do 
  cat $FN | wc -l 
done

Дубль твоей темы удален модераторами.

Зачем ты создаёшь ещё одну тему?

kostik87 ★★★★★
()
Последнее исправление: kostik87 (всего исправлений: 1)
Ответ на: комментарий от sigurd

Благодарю. Глядя на стоимость переходника появляется мысль взять б/у монитор )

skinner
()
Вы не можете добавлять комментарии в эту тему: топик перемещен в архив.