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)

Ответ на: комментарий от 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
() автор топика
Ответ на: комментарий от 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)
Ответ на: комментарий от 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 ★★★★★
()