LINUX.ORG.RU

Нужна помощь с bash скриптом, нужна отмена вывода ошибки

 , ,


0

2

Всех приветствую, нужна помощь с скриптом. ОС Alt Linux Рабочая станция Linux host-15tstalt 5.10.128-std-def-alt1 #1 SMP Fri Jul 8 14:39:36 UTC 2022 x86_64 GNU/Linux Имеется скрипт с таким содержимым.

#! /bin/bash
source /media/dirlab/coutlistuser
find /media/dirlab -user $43 -exec sh -c "file '{}' | grep -q 'ELF'" \; -print | wc -l

Файл /media/dirlab/coutlistuser это автоматически генерируемый файл с содержимым по пользователям. Нужен для того что бы проверять появились пользователи новые или нет. Выглядит примерно так

p1=polkitd	
p2=_avahi	
p3=_ldm	
p4=_chrony	
.....	
p49=mxvel	
p50=ivanov	
p51=petrov	
p52=sidorov	
p53=pupkin 

find /media/dirlab - поиск в нужном нам каталоге -user $43 -exec sh -c «file ‘{}’ | grep -q ‘ELF’» ; -print - условие при котором происходит поиск исполняемых ELF файлов по владельцам. Источник с пользователями как раз для этого. -print | wc -l - вывод численного количества ELF файлов.

Возникает несколько ошибок/задач которые не знаю как исправить.

  1. Если переменная с пользователями ($p54 и больше) превышает количество существующих пользователей в системе появляется ошибка
find: ‘-exec’ is not the name of a known user

Понятно почему появляется, но нужно что бы информация о несуществующем пользователе не выводилась.

  1. Если пользователь существует но нет файлов ELF в каталоге скрипт указывает количество файлов
0

Это пустое количество тоже выводить не нужно.

Пробовал обернуть это в значения «если то»

#!/bin/bash
source /media/dirlab/coutlistuser

if
 COUNT=`find /media/dirlab -user $p51 -exec sh -c "file '{}' | grep -q 'ELF'" \; -print | wc -l `
then [ $COUNT -eq 0 ]
else 
echo "$p51 $COUNT"
fi

Но вывод информации вообще перестает происходить даже если ELF файлы есть.

Кто знает как сделать 1 и 2 пункт?

нужно что бы информация о несуществующем пользователе не выводилась

find … 2>/dev/null подавляет вывод ошибок

pihter ★★★★★
()

Это пустое количество тоже выводить не нужно

Вот тут не понял, ты хочешь чтоб если ноль – то вообще ничего не выводилось?

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

Пробовал, работает не так как думал.

host-15tstalt labs # find /media/dirlab -user $p55 -exec sh -c "file '{}' | grep -q 'ELF'" \; -print | wc -l 2>/dev/nul

find: ‘-exec’ is not the name of a known user
0

И отвечаю на следующий вопрос. Да, есть НОЛЬ, то информацию не выводим. Данные нужно показывать только есть число больше нуля.

maxvel911
() автор топика

1) "$p51" надо в кавычках писать

2)

then [ $COUNT -eq 0 ]
Это какая-то чушь. Во-первых, ты где-то if забыл. Во-вторых, опять переменная без кавычек.

Ну и в целом: ты какую-то странную вещь пытаешься сделать, мне кажется подход к задаче в целом неправильный.

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

работает не так как думал.

Потому что ты подавляешь вывод ошибок у wc, а не у find'а.

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

Вот этот твой $p55 и прочие подобные переменные - оно где определяется? Или у тебя отдельные скрипты под каждую переменную?

Или задача стоит обойти всех пользователей по тому файлу, что source'ится и поискать для них ELF'ы? Можешь внятно описать, что ты хочешь?

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

Вот эти переменные $p55 да, они прописываются в соурсе.

Да, отдельные скрипты под каждую переменную. Я не придумал как это сделать «красиво». Да, задача пройти всех пользователей и проверить есть ELFы или нет.

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

Т.е., то, от чего все идет - список пользователей из файла. Тебе требуется цикл for, которому будет передаваться содержимое списка (cat /путь/к/файлу), а дальше для каждого значения из списка будет выполняться find. Но, если я верно понял, в списке могут присутствовать несуществующие в системе пользователи и на это тоже надо делать проверку?

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

Да, именно так. Пользователи могут появляться новые, и их нужно проверять. Сейчас получилось примерно следующее

#!/bin/bash
source /media/dirlab/coutlistuser
#vol1="find: ‘-exec’ is not the name of a known user"
if COUNT=`find /media/dirlab -user $p55 -exec sh -c "file '{}' | grep -q 'ELF'" \; -print 2>/dev/nul | wc -l`
then
echo "ELF File $p55 $COUNT"
fi

Отрабатывает от части правильно, на не существующих пользователей ошибку не выдает. Но теперь нужно избавиться от «нуля» если ELFов нет в каталоге.

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

Ответы которые выдает скрипт Правильный вид. Когда пользователь есть и файлы ELF есть.

ELF File sidorov 3

Не правильный вид, либо пользователя нет, либо файлов нет. Информации не должно быть.

ELF File  0

Все эти значения по крону потом будут проверяться 2 раза в день. И что бы лог не засирать нулями и не нужными данными их не нужно писать.

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

Давай все же строить скрипт, исходя из задачи целиком. Стоит задача обойти сгенерированный список? Или так и собираешься держать десятки скриптов, отличающихся парой букв?

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

Стоит задача проверять каталог по владельцам ELF файлов. Для генерации списка пользователей использую такой скрипт.

#! /bin/bash
# получим список пользователей в файл
cut -d: -f1 /etc/passwd > listuser
# в полученый список пользователей добавляем численный столбец и знак =
cat listuser | sed '{$D; =}' | sed 'N; s/\n/ /' | awk '{printf $1 "=" $2 "\t" $3 "\n"}' > /media/dirlab/coutlistuser
#для правильной отработки переменных в начало каждой строки добавим символ p
sed -i '1,60s/^/p/' /media/dirlab/coutlistuser

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

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

for i in $(cut -d: -f1 /etc/passwd)
do
ИЩЕМ ФАЙЛЫ для "${i}"
done



Так?

YAR ★★★★★
()

Нужен для того что бы проверять появились пользователи новые или нет.

Эм… а сверять /etc/passwd не пробовал? Все локальные пользователи в нём.

Vsevolod-linuxoid ★★★★★
()

Или тебе нужно отслеживать факт наличия сессии пользователя, а не факт появления нового пользователя?

Vsevolod-linuxoid ★★★★★
()
Ответ на: комментарий от YAR

Да, от части это работает, здесь прям хорошая оптимизация. Получилось нечто следующее

#!/bin/bash
for i in $(cut -d: -f1 /etc/passwd)
do
find /media/dirlab -user "${i}" -exec sh -c "file '{}' | grep -q 'ELF'" \; -print | wc -l
done

Но вывод ужасен

host-15tstalt labs # sh 09.sh 
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
3
1
3
0
0

Как теперь можно прописать значениям отличным от нуля наименование владельца и убрать все нули?

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

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

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

Тогда уж после цикла - ему ведь надо еще выводить текст и юзера, а это надо в рамках цикла оформить.

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

Пока я еще не ушел завтракать, напишу. Твою задачу можно решать двумя путями: брать список пользователей и для пользователя искать нужные файлы, либо брать список имеющихся файлов (по определенным условиям) и смотреть, какому пользователю они принадлежат. Ну и считать число совпадений для каждого пользователя. Первый вариант - это то, что мы выше разбирали. Второй вариант - тебе как домашнее задание:

rain@walkbook:~$ find /tmp -maxdepth 1 -exec sh -c 'file {} | grep -q PNG' \; -ls 2>/dev/null | awk '{t[$5]+=1} END {for (a in t) print "PNG FILE", a, t[a]}'
PNG FILE firefox 8
PNG FILE rain 37

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

Да, так убирает нули

#!/bin/bash
for i in $(cut -d: -f1 /etc/passwd)
do
find /media/dirlab -user "${i}" -exec sh -c "file '{}' | grep -q 'ELF'" \; -print | wc -l | grep -v "^0$"
done

вывод

3
1
3

Как присвоить значениям - пользователей?

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

Твой пользователь у тебя в $i, ведь ты по нему ищешь.

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

Да, задача пройти всех пользователей и проверить есть ELFы или нет.

То есть ты хочешь 50 раз обходить всё дерево файловой системы, каждый раз ища там разных юзеров? Можно обойти один раз, собирая сразу статистику по всем, и /etc/passwd для этого не нужен, сохранять результат можно по uid-ам. А затем уже найденное сопоставить с именами пользователей, если они тебе нужны.

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

Во-вторых, опять переменная без кавычек.

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

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

С одной стороны так, с другой - переменная без кавычек без обоснования это к проблемам, и лучше не приобретать дурных привычек. Тут запутывающий синтаксис: кажется будто кавычки это добавление какого-то функционала к парсингу, который незачем без нужды вызывать. На самом деле наоборот: переменная в кавычках должна быть дефолтом - это тупо подстановка строки целиком, а без кавычек - только когда надо распарсить в ней пробелы и сделать вид что там вообще ничего нет если переменная пустая. Если пробелов нет и строка не пустая, то результат одинаковый, но зачем парсить пробелы если их нет? Вот и ставишь кавычки.

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

На самом деле

На самом деле в выражениях [ $v -eq ... без кавычек хорошая привычка дополнительно шлифовать алгоритм, чтобы там не могло появиться что-либо кроме целых чисел. Так в данном случае 'wc -l' всегда целочисленен, в этом надо убедиться и работать далее спокойно. А с кавычками/без больше мороки и полезного не сколько с пробелами, сколько с масками, потому, скажем ${v#$m} и ${v#«$m»} и «${v#$m}» etc  — совсем разное и по разному нужное.

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

Приветствую. А если исходить из все же бинарности файлов ELF. К примеру в проверяемом каталоге будет создан простой файл

touch ELF

вывод

-rw-rw----  1 ivanov  dirlab_gp     0 авг 31 17:52 01file_ivanov
-rw-rw----  1 pupkin  dirlab_gp    10 авг 31 17:52 01file_pupkin
-rw-rw----  1 pupkin  dirlab_gp    13 авг 31 17:52 02file_pupkin
-rwxrwx--x+ 1 root    root        603 сен  5 16:47 coutlistuser
-rw-rw----+ 1 root    root          0 сен 20 15:57 ELF
-rwxrwx---  1 ivanov  dirlab_gp    45 авг 31 17:52 file_from_ivanov
-rwxrwx---  1 ivanov  dirlab_gp    45 авг 31 17:52 file_from_ivanov_cp1
-rwxrwx---  1 ivanov  dirlab_gp    45 авг 31 17:52 file_from_ivanov_cp2
-rwxrwx---  1 petrov  dirlab_gp    45 авг 31 17:52 file_from_petrov
-rwxrwx---  1 petrov  dirlab_gp    45 авг 31 17:52 file_from_petrov_cp1
-rwxrwx---  1 sidorov dirlab_gp    47 авг 31 17:52 file_from_sidorov
-rwxrwx---+ 1 ivanov  dirlab_gp 27608 авг 31 17:52 ivanov_elf.c_01
-rwxrwx---+ 1 ivanov  dirlab_gp 27608 авг 31 17:52 ivanov_elf.c_02
-rwxrwx---+ 1 ivanov  dirlab_gp 27608 авг 31 17:52 ivanov_elf.c_03
-rw-rw----  1 root    dirlab_gp  4241 сен 20 15:59 logfile
-rwxrwx---+ 1 petrov  dirlab_gp 27608 авг 31 17:52 petrov_elf.c_01
-rwxrwx---+ 1 sidorov dirlab_gp 27608 авг 31 17:52 sidorov_fff.c_01
-rwxrwx---+ 1 sidorov dirlab_gp 27608 авг 31 17:52 sidorov_fff.c_02
-rwxrwx--x+ 1 sidorov dirlab_gp 27608 авг 31 17:52 sidorov_fff.c_no_pie

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

#!/bin/bash
for i in $(cut -d: -f1 /etc/passwd)
do
find /media/dirlab -user "${i}" -exec  sh -c "file {} \; | grep -q 'ELF'" \; -print | wc -l | grep -v "^0$" 
done
ELF FILE ivanov 3
ELF FILE petrov 1
ELF FILE sidorov 3
ELF FILE root 1

root -1 тот самый обычный ELF. Как сделать так, что бы скрипт не видел обычные файлы с этим названием?

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

У тебя grep реагирует не на тип файла, а на его имя. Чтобы file не выводил имя - используй ключ -b.

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

С ключом -b работет не корректно. вывод не правильный

2
6
2
6

Сделал таким образом

#!/bin/bash
for i in $(cut -d: -f1 /etc/passwd)
do
find /media/dirlab -type f  -user "${i}" -exec sh -c "file {} | grep -Pi ': elf (32|64)-bit' > /dev/null" \; -print | wc -l | grep -v "^0$"
done

Так сработало. Показывает только эльфов без имен названий.

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

А если пользователь создаст файл с ": ELF 64-bit" в названии? :)

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

С ключом -b работет не корректно

Хотелось бы увидеть причину, я так её не вижу с ходу.

Сделал таким образом

Проверил на /home и ужаснулся. Оно сканирует все файлы в каталоге столько раз, сколько пользователей, да ещё на каждый файл вызывает sh+file+2*grep. Результата не дождался. Так что вот, с максимальной группировкой аргументов для sh+file, с внутренним «grep» и встроенным теперь stat в bash:

#!/usr/bin/env bash

PTH="/media/dirlab"

export NL=$'\n' R="^[ ]*ELF [36][24]-bit LSB executable, "
LIST=($(find "$PTH" -type f -exec bash -c '\
while read f; do
        read ft
        [[ "$ft" =~ $R ]] && stat -c "%U" "$f"
done < <(file -F"$NL" "$@")
' '{}' +))
declare -Ai UF
for f in "${LIST[@]}"; do UF[$f]+=1; done
for u in "${!UF[@]}"; do echo "$u: ${UF[$u]}"; done
vodz ★★★★★
()
Ответ на: комментарий от YAR

Вызывать bash на каждый найденный файл?

Прежде чем комментить стоило бы внимательно прочитать скрипт и man find на предмет "-exec '{}' +"

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

А, просмотрел. В любом случае это проще:

$ find /tmp -type f -printf '%u :' -exec file -b {} \; 2>/dev/null | mawk '/PNG/{t[$1]+=1} END {for (a in t) print "PNG FILE", a, t[a]}'
PNG FILE rain 37
PNG FILE firefox 9

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

В любом случае это проще:

Осталось убрать плюхи с названием PNG и пробелом в имени...

Кстати, у меня вот затесались (сам не ожидал) файлы с апострофом (музыка Прокофьева), так что предыдущей скрипт тоже у вас глючил.

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

Осталось убрать плюхи с названием PNG и пробелом в имени

У меня просто куча картинок в /tmp, на них и тренировался. Думаю, тут уж ТС справится сам.

так что предыдущей скрипт тоже у вас глючил.

Да, и не только на этом - сказывается копирование изначального кода.

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

Думаю, тут уж ТС справится сам.

Сомневаюсь.

Да, и не только на этом - сказывается копирование изначального кода.

А мне кажется, что вы даже не пробовали. Я вот пробовал до публикации в виде одной строки и скрипт кардинально изменился, все эти $NL и два read не с проста.

А вообще, мне кажется, что это у ТС-а лабораторка на предмет знания bash, а у вас по сути его считай и нет :)

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

Блин, всё время забываю насчёт необходимого еще одного аргумента для -exec {} +. Заодно сделал уж точно без ограничений на имена файлов.

#!/usr/bin/env bash

PTH="/media/dirlab"
export R="ELF [36][24]-bit LSB executable, "

LIST=($(find "$PTH" -type f -exec bash -c '\
while IFS= read -r -d "" f; do
	read ft
	[[ ${ft#$R} != "$ft" ]] && stat -c "%U" "$f"
done < <(file -Nr -0 -F "" "$@")
' "$0" '{}' +))
declare -Ai UF
for f in "${LIST[@]}"; do UF[$f]+=1; done
for u in "${!UF[@]}"; do echo "$u: ${UF[$u]}"; done

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