Nowe posty

Autor Wątek: grep  (Przeczytany 3555 razy)

Offline 1709

  • Users
  • Guru
  • *****
  • Wiadomości: 2547
  • 1709
    • Zobacz profil
grep
« dnia: 2016-07-23, 18:05:18 »
Z czystej ciekawosci chcialem zadac pytanie

Plik1
DoAsRoot 2.1.1-9
FlvToMp3 1.2.1-4
akonadi 1.13.0-2
akonadi 1.15.0-2
akonadi-devel 1.15.0-2

Skrypt:
#!/bin/bash

# first line
ac=$(cat `pwd`/plik1| head -n1)

echo " -- $ac"

# name
ad=$(awk '{print $1}' <<< "$ac")

# count
ae=$(grep "$ad " `pwd`/plik1 | wc -l)

if [[ "$ae" == "1" ]]; then
                        echo "If ... Yes"
                         echo "Removed : $ad"
                         echo "------------------"
                         echo -e "$(cat `pwd`/plik1 | grep -v "$ad ")" | grep "\S"  > plik1
                         echo "------------------"
                         echo "exit status: $?"

      fi

cat `pwd`/plik1 | wc -l

To powoduje że nadpisany plik1 jest pusty
$ ./skrypt
 -- DoAsRoot 2.1.1-9
If ... Yes
Removed : DoAsRoot
------------------
------------------
exit status: 0
0

Jak pozbede sie  "  |  grep "\S"   "  to do pliku coś zostaje zapisane ( 4 linie )

$ ./skrypt
 -- DoAsRoot 2.1.1-9
If ... Yes
Removed : DoAsRoot
------------------
------------------
exit status: 0
4

$ cat plik1
FlvToMp3 1.2.1-4
akonadi 1.13.0-2
akonadi 1.15.0-2
akonadi-devel 1.15.0-2

grep "\S" użyłem celowo ,   http://stackoverflow.com/questions/16414410/delete-empty-lines-using-sed
bo echo tworzy linie która powoduje błąd przy zliczaniu pustego pliku (wc -l)
od dzisiaj będę używał  " sed -i "/^${ad} /d" `pwd`/plik1  "
Ale czy ktoś umiałby wytłumaczyć czemu grep "\S" powoduje problem skoro jakieś wyjście komendy
echo -e "$(cat `pwd`/plik1 | grep -v "$ad ")" | grep "\S"
 bez zapisu do pliku istnieje ?

$ ./skrypt
 -- DoAsRoot 2.1.1-9
If ... Yes
Removed : DoAsRoot
------------------
FlvToMp3 1.2.1-4
akonadi 1.13.0-2
akonadi 1.15.0-2
akonadi-devel 1.15.0-2
------------------
exit status: 0
5

Edytowane:
- plik1 nie moge nadpisać komendą, ale moze zapisać wyjscie do innego pliku,
czemu dodanie | grep robi taki problem ?
Zdaję sobie sprawe ze samo echo -e "$(cat `pwd`/plik1 | grep -v "$ad ")"
 jest w pewien sposób obejsciem, bo nie mozna nadpisac tego samego pliku który jest otwarty i jego wyjscie przekierowane,
ale przecież samo  echo -e "$(cat `pwd`/plik1 | grep -v "$ad ") działa.
PS: Brak polskiej czcionki, nie jest to brak lenistwa, a jej brak w systemie i brak czasu na reczne poprawki.

Offline Paweł Kraszewski

  • Administrator
  • Guru
  • *****
  • Wiadomości: 2811
  • Lenistwo jest matką potrzeby = babcią wynalazku
    • Zobacz profil
Odp: grep
« Odpowiedź #1 dnia: 2016-07-23, 19:47:50 »
Na razie OT:

jesteś świadom, że cat `pwd`/plik to to samo co cat plik?

Mniej OT:

W linijce z echo -e masz porąbane cudzysłowy - cudzysłów dookoła $ad kończy cudzysłów od echo.

Rozumiem, że to wyciachany kawałek czegoś większego. Moja poprawka wygląda tak:
#!/bin/bash

read ad av < <(head -n1 plik1)
read ae < <(egrep "^$ad\s" plik1 | wc -l)
echo " -- $ad / $av / $ae"

if [ "$ae" == "1" ]; then
echo "If ... Yes"
echo "Removed : $ad"
echo "------------------"
sed -i "/^$ad\s/d" plik1
        echo "------------------"
        echo "exit status: $?"
fi

cat plik1 | wc -l

* sed -i pracuje in-place, czyli modyfikuje plik na którym pracuje.
* read ad av < <(head -n1 plik1) odpala podproces z nawiasu i kolejne tokeny wyniku podstawia do kolejnych zmiennych. To jest co innego niż head -n1 plik1 | read ad av, bo w drugim przypadku zmienne są tworzone w podprocesie i znikają po jego zakończeniu.
* Wykonanie kończy się na akonadi przez warunek "$ae" == "1" - ale rozumiem, że to fragment czegoś większego.
« Ostatnia zmiana: 2016-07-23, 20:31:49 wysłana przez Paweł Kraszewski »
Paweł Kraszewski
~Arch/Void/Gentoo/FreeBSD/OpenBSD/Specjalizowane customy

Offline 1709

  • Users
  • Guru
  • *****
  • Wiadomości: 2547
  • 1709
    • Zobacz profil
Odp: grep
« Odpowiedź #2 dnia: 2016-07-23, 20:31:49 »
Cytuj
Na razie OT:
jesteś świadom, że cat `pwd`/plik to to samo co cat plik?
A w jakim sensie to to samo ?
- Jeśli chodzi Ci że cat zadziała tak samo jeśli plik jest w tym samym katalogu to się zgodze.
- Jeśli plik umieściłem w podkatalogu np. "Ustawienia" i daje katalog ze skryptem/programem komuś to czesto korzystam z  cat  `pwd`/Ustawienia/plik
 chociaż jakbym podał cat Ustawienia/plik to też by zadziałało.
PS: Brak polskiej czcionki, nie jest to brak lenistwa, a jej brak w systemie i brak czasu na reczne poprawki.

Offline Paweł Kraszewski

  • Administrator
  • Guru
  • *****
  • Wiadomości: 2811
  • Lenistwo jest matką potrzeby = babcią wynalazku
    • Zobacz profil
Odp: grep
« Odpowiedź #3 dnia: 2016-07-23, 22:23:39 »
Cytat:  link=topic=24612.msg132815#msg132815 date=1469298709
A w jakim sensie to to samo ?

instrukcja_działająca_na_pliku plik : szuka pliku w katalogu bieżącym  - jako ścieżka względna
instrukcja_działająca_na_pliku `pwd`/plik : szuka pliku w katalogu bieżącym - jako ścieżka bezwzględna

Przy okazji - rozszerz trochę swój algorytm (pokaż go "z większej odległości") - bo mam wrażenie, że coś strasznie na około robisz...

Na przykład bez "grzebania" w pliku i wielokrotnego czytania go:
#!/bin/bash

while read ae ad
do
echo " -- $ad / $ae"
if [ "$ae" == "1" ]; then
echo "If ... Yes"
echo "Removed : $ad"
echo "------------------"
echo "------------------"
echo "exit status: $?"
fi
done < <(cut -d" " -f1 plik1 | sort | uniq -c)
Paweł Kraszewski
~Arch/Void/Gentoo/FreeBSD/OpenBSD/Specjalizowane customy

Offline 1709

  • Users
  • Guru
  • *****
  • Wiadomości: 2547
  • 1709
    • Zobacz profil
Odp: grep
« Odpowiedź #4 dnia: 2016-07-24, 00:48:28 »
Cytuj
Przy okazji - rozszerz trochę swój algorytm (pokaż go "z większej odległości") - bo mam wrażenie, że coś strasznie na około robisz...


Skrypt ma na celu pokazanie listy pakietów (nazwa + wersja), tylko tych w najnowszej wersji,
czyli zamiast
DoAsRoot 2.1.1-9
FlvToMp3 1.2.1-4
FlvToMp3 1.2.3-5

ma być
DoAsRoot 2.1.1-9
FlvToMp3 1.2.3-5

#!/bin/bash


# usunięcie plików stworzonych wczesniej
rm 1.32bit
rm 2.32bit


# Ostrzezenie jeśli występują duplikaty pakietów
a1a=$(uniq -D 32bit.rpm.lista3 | wc -l)

if [[ "$a1a" -gt "1" ]]; then
echo "-------------"
echo -e "Warning: Występuje duplikat pakietu \n$(uniq -D 32bit.rpm.lista3)"
echo "-------------"
fi

# Usuniecie powtarzajacych sie linii oraz posortowanie wedlug pierwszej kolumny
sort 32bit.rpm.lista3 | uniq | sort -k1 > 1.32bit

#--------------------------
# W pliku występują czasami takie same nazwy pakietów z różnymi wersjami
# mnie zależy żeby w pliku były pakiety tylko z najnowszą wersją.
# W tym celu
# 1. przeniose pakiety (nazwa + wersja) do nowego pliku które się nie powtarzają (z nazwy)
# 2. a te które się powtarzają przy pomocy "sort -V | tail -n1" wyłuskam pakiet z najwyżym
#    numerkiem i dopisze do nowego pliku.
# 3. oczywiscie pakiety moge sprawdzać linia po linii i potem użyć "sort | uniq"
#    optymalizacja zależy od sytuacji, więc tu ta metoda nie musi się sprawdzić,
# ponieważ więcej czasu może zajmie ciągłe kasowanie w pliku niż sortowanie i usunięcie powturzeń raz
#    ale chciałem spróbować usuwając z listy pakiety które już są w nowym pliku


# Zawartosc
aa=$(cat `pwd`/1.32bit)

# Liczba lini w pliku
ab=$(cat `pwd`/1.32bit | wc -l)

# petla
for i in `seq 1 $ab`  #`seq 1 $ab`
do
# pierwsza linia
ac=$(cat `pwd`/1.32bit | head -n1)

echo "$i / $ab - $ac"

# nazwa
ad=$(awk '{print $1}' <<< "$ac")

# liczba wystąpień nazwy w pliku,
# spacja w zmiennej jest specjalnie aby nazwa była precyzyjna
ae=$(grep "^${ad} " `pwd`/1.32bit | wc -l)


# Filtrowanie i zapisanie danych do nowego pliku
#
# 1. Jezeli nazwa w pliku wystepuje tylko raz
if [[ "$ae" == "1" ]]; then

# Zapis do nowego pliku
echo "$ac" >> 2.32bit

# 3. Usuwanie ze starego pliku
#
# nie dziala --> echo -e "$(cat `pwd`/1.32bit | grep -v "$ad ")" | grep "\S" > `pwd`/1.32bit
# dziala, --> echo -e "$(cat `pwd`/1.32bit | grep -v "$ad ")" > `pwd`/1.32bit
# ale plik nigdy nie osiagnie "0" linii (winny: echo)
#
# sed działa świetnie i jest krótkie, tylko chwilowo tworzy plik tymczasowy,
# a głównym celem było unikanie zapisu do plików w celu wyeliminowania spowolnień i korzystania z dysku.
#
sed -i "/^${ad} /d" `pwd`/1.32bit

# Jezeli nie ma nazwy, to skrypt zostal żle napisany
elif [[ "$ae" == "0" ]]; then
echo "Blad: Skrypt zostal źle napisany"
exit 1

# 2. Jeżeli nazwa występuje w pliku więcej niż raz
else
# wyłuskanie linii tylko z najwyższą wersją
af=$(grep "^${ad} " `pwd`/1.32bit | sort -V | tail -n1)

# Zapis do nowego pliku
echo "$af" >> 2.32bit


# Usuwanie ze starego pliku
sed -i "/^${ad} /d" `pwd`/1.32bit
fi

# Oczywiscie nazwy w pliku skończą się szybciej,
# bo część linii powtarzających się z nazwy została usunięta
# dlatego sprawdzimy czy plik faktycznie jest już pusty
xx=$(cat `pwd`/1.32bit | wc -l)
if [ "$xx" = "0" ]; then
echo "Zadziałał break"
break
fi

done

echo "Gotowe: Wynik możesz odczytać w `pwd`/2.32bit "
Edit
- Poprawiłem ostatni komentarz
- poprawiłem wyrażenie grep
PS: Brak polskiej czcionki, nie jest to brak lenistwa, a jej brak w systemie i brak czasu na reczne poprawki.

Offline Paweł Kraszewski

  • Administrator
  • Guru
  • *****
  • Wiadomości: 2811
  • Lenistwo jest matką potrzeby = babcią wynalazku
    • Zobacz profil
Odp: grep
« Odpowiedź #5 dnia: 2016-07-24, 10:04:16 »
Czyli strasznie na około chcesz zrobić:

sort --sort=version -r plik1 | sort  -u -k1,1

* Musi być potok dwóch sortów, bo nie można w jednym sorcie zrobić reverse i unique, a potrzebujemy ostatni unikalny a nie pierwszy. Po połączeniu konstrukcja zwraca listę najstarszych wersji a nie najmłodszych.
* Sortowanie po version poprawnie rozpoznaje kolejność wersji, wie że 10.0.0 jest po 9.0

Dla

akonadi-devel 1.15.0-2
akonadi 1.13.0-2
akonadi 1.15.0-2
DoAsRoot 2.1.1-9
FlvToMp3 1.2.1-4
FlvToMp3 1.2.3-5
daje wynik
akonadi 1.15.0-2
akonadi-devel 1.15.0-2
DoAsRoot 2.1.1-9
FlvToMp3 1.2.3-5

Można nawet pokusić się o zrobienie tak:
#!/bin/bash

sort --sort=version -r plik1 >plik1.tmp
sort -u -k1,1 plik1.tmp > plik1.nowe
comm -13 --nocheck-order plik1.tmp plik1.nowe > plik1.stare
rm plik1.tmp
W wyniku powstaje plik plik1.nowe zawierający najnowsze wersje i plik plik1.stare zawierający wersje przestarzałe.
« Ostatnia zmiana: 2016-07-24, 10:16:55 wysłana przez Paweł Kraszewski »
Paweł Kraszewski
~Arch/Void/Gentoo/FreeBSD/OpenBSD/Specjalizowane customy

Offline 1709

  • Users
  • Guru
  • *****
  • Wiadomości: 2547
  • 1709
    • Zobacz profil
Odp: grep
« Odpowiedź #6 dnia: 2016-07-25, 11:42:52 »
Dziękuje !    ;D
sort --sort=version -r plik1 | sort  -u -k1,1
czy to samo
sort -V -r plik1 | sort  -u -k1,1
Działa idealnie w tym przypadku i jest o wiele szybsze niż użycie skryptu bash z pętlą.


Czyli sortuje wszystko według wersji od najwiekszej liczby do największej
sort --sort=version -r plik1

stosuje uniq tylko od pierwszej kolumny do pierwszej kolumny
sort  -u -k1,1


_________________________________________________
Fajnie że działa,
bo manual oraz help nie zbyt wiele piszą o zasadzie działania klucza i większość poradników podaje tylko proste przykłady,
co używanie klucza czasami nie daje oczekiwanych efektów i w konsekwecji wiąże się z bólem głowy.

Więc jeśli pozwolicie rozwinę trochę post
użycie
sort -k1,1 plik
Powinno tylko posortować według pierwszej kolumny, nie ruszając kolejności pozostałych kolumn ?
PS: Brak polskiej czcionki, nie jest to brak lenistwa, a jej brak w systemie i brak czasu na reczne poprawki.

Offline Paweł Kraszewski

  • Administrator
  • Guru
  • *****
  • Wiadomości: 2811
  • Lenistwo jest matką potrzeby = babcią wynalazku
    • Zobacz profil
Odp: grep
« Odpowiedź #7 dnia: 2016-07-25, 13:07:16 »
Cytat:  link=topic=24612.msg132825#msg132825 date=1469439772
użycie
sort -k1,1 plik
Powinno tylko posortować pierwszą kolumnę, nie ruszając pozostałych kolumn ?

Nie, sortuje wszystkie kolumny, ale według pierwszej. To, czy jest -k1,1 czy -k1 ma znaczenie przy parametrze -s (stable)
Data:
zenek ala
adam basia
zenek zofia
adam wanda
zenek beata
adam asia

> sort -k1 -s data  
adam asia
adam basia
adam wanda
zenek ala
zenek beata
zenek zofia
> sort -k1,1 -s data
adam basia
adam wanda
adam asia
zenek ala
zenek zofia
zenek beata
Paweł Kraszewski
~Arch/Void/Gentoo/FreeBSD/OpenBSD/Specjalizowane customy

Offline 1709

  • Users
  • Guru
  • *****
  • Wiadomości: 2547
  • 1709
    • Zobacz profil
Odp: grep
« Odpowiedź #8 dnia: 2016-07-25, 14:47:32 »
Dzięki !
PS: Brak polskiej czcionki, nie jest to brak lenistwa, a jej brak w systemie i brak czasu na reczne poprawki.

Offline 1709

  • Users
  • Guru
  • *****
  • Wiadomości: 2547
  • 1709
    • Zobacz profil
Odp: grep
« Odpowiedź #9 dnia: 2016-07-26, 22:47:04 »
Cytuj
Można nawet pokusić się o zrobienie tak:
...
W wyniku powstaje plik plik1.nowe zawierający najnowsze wersje i plik plik1.stare zawierający wersje przestarzałe.

Nie jestem pewien ale to chyba miało być coś takiego ?
sort --sort=version -r plik1 | sort -u -k1,1 > plik1.nowe
comm -3 --nocheck-order plik1 plik1.nowe  > plik1.stare

Co z plik1
0ad 0.0.19-1
0ad-data 0.0.19-1
2ManDVD 1.8.5-2
4Pane 3.0-2
5ball 0.41-2
5ball 0.41-3

Daje wynik
5ball 0.41-2

__________________
Tak się teraz zainteresowałem, bo skończyłem poprawiać skrypt który ma porównać dwa repozytoria,
dodałem te ... sortowanie
i dodałem twój skrypt jako bonus-  dodatkowe info o starych pakietach które można usunąć i pomoże zrobić porządek w repo.

Edytowane:
ech... chybadalej cos nie tak
gdy w pliku jest
akonadi-devel 1.15.0-2
akonadi 1.13.0-2
akonadi 1.15.0-2
DoAsRoot 2.1.1-9
FlvToMp3 1.2.1-4
FlvToMp3 1.2.3-5
To nie działa juz tak ladnie.

Edytowane:
Dobra, oba pliki musza być pierw posortowane
sort plik1 >  plik2
sort --sort=version -r plik1 | sort -u -k1,1 | sort > plik1.nowe
comm -3 --nocheck-order plik2 plik1.nowe  > plik1.stare
I wtedy otrzymam
akonadi 1.13.0-2
FlvToMp3 1.2.1-4
PS: Brak polskiej czcionki, nie jest to brak lenistwa, a jej brak w systemie i brak czasu na reczne poprawki.