Nowe posty

Autor Wątek: Prozaiczny problem - zlepić kilka zmiennych w jedno wywołanie  (Przeczytany 3884 razy)

kormikez

  • Gość
Problematyczny fragment skryptu ma wyciąć z outputu danego polecenia jego daną kolumnę i wiersz, np. ./skrypt.sh "ps aux" 11 4 ma wyciąć nazwę 4 procesu (11 kolumna) z listy. Rozwiązanie nieskomplikowane: ps aux |awk 'NR==4 {print $11}', problem w podaniu zmiennych w samym skrypcie. Mam wyciągane z linii poleceń m.in. takie zmienne:

$command=$1
$awk_col="{print\\$$3}"
$awk_row="NR==$4"


Składam to w jedną całość:

cmd="$command |awk '$awk_row $awk_col'"

I wywołuję:

$cmd

Efekt: ps zwraca błąd:

ERROR: Garbage option.


No OK, nie wiem skąd taki błąd, ale ostatecznie nie muszę robić tego w ten sposób - dlaczego nie wywołać polecenia bez tworzenia zmiennej? Zatem po prostu:

$command |awk '$awk_row $awk_col'

Nie działa - no tak, te apostrofy sprawiają, że $awk_row i $awk_col nie będą żadnymi wartościami. Poprawmy:

$command |awk \\'$awk_row $awk_col\\'

Efekt:

awk: 1: unexpected character '''


I w tym momencie ręce mi opadły. Mam nadzieję, że nieco bardziej zaawansowani w bashu będą potrafili wskazać, gdzie robię błąd, a może zaproponować całkiem inne i lepsze rozwiązanie. Dzięki z góry za wszelkie wskazówki!

Offline ultr

  • Users
  • Guru
  • *****
  • Wiadomości: 1177
    • Zobacz profil
Prozaiczny problem - zlepić kilka zmiennych w jedno wywołanie
« Odpowiedź #1 dnia: 2009-03-23, 12:28:01 »
1)
Masz 3 parametry, więc skąd $4?


2)
> $awk_col="{print\\$$3}"

Po "print" powinna chyba być spacja.


3)
Po co robić tyle zmiennych? Znacznie czytelniejsze jest takie polecenie:

#!/bin/bash
$1 | awk "NR==$3 { print \\$$2 }"
4)
"ps aux" raczej nie powinno być argumentem. Lepiej napisać:
#!/bin/bash
ps aux | awk "NR==$2 { print \\$$1 }"

arctgx

  • Gość
Prozaiczny problem - zlepić kilka zmiennych w jedno wywołanie
« Odpowiedź #2 dnia: 2009-03-23, 12:31:59 »
Mniej więcej może wyglądać to tak:
eval "$1" | awk 'NR=='$2' {print $'$3'}'
Dolar zamaskowany apostrofem tracił swoje znaczenie, dlatego trzeba było na chwilę dać zamykający, by powłoka mogła zinterpretować go, a potem otworzyć apostrof dla dalszej części polecenia awka.

kormikez

  • Gość
Prozaiczny problem - zlepić kilka zmiennych w jedno wywołanie
« Odpowiedź #3 dnia: 2009-03-23, 13:07:11 »
Dzięki za odpowiedzi.

ultr:
Jest też trzeci parametr, ale nie podawałem go tu, bo w tej części skryptu nie ma nic do rzeczy, tak jak to przedstawiłem tutaj rzeczywiście powinno być to $2 i $3. Co do spacji, nie jest ona konieczna, sprawdzałem. A zmienne są mi potrzebne dla czytelności, ten skrypt jest odrobinę dłuższy - tutaj jest tylko jego fragment. Co do punktu 4. nie bardzo rozumiem, co masz na myśli. "ps aux" to tylko przykładowe polecenie, musi być schowane w zmiennej.

arctgx:
To co napisałeś działa, jest tylko jeden szkopuł. Chcę żeby część z NR==zmienna wywoływała się opcjonalnie, tzn. część NR=='$2' byłaby ukryta pod zmienną, która albo będzie, albo będzie pusta (i wtedy awk wylistuje całą kulmnę). Stąd chcę żeby to było coś takiego:
awk_row='NR=='$2
eval "$1" | awk '$awk_row {print $'$3'}'
I teraz jak go zmusić żeby przed całością był apostrof, a jednocześnie zmienna $awk_row pozostała interpretowana jako zmienna? :)

arctgx

  • Gość
Prozaiczny problem - zlepić kilka zmiennych w jedno wywołanie
« Odpowiedź #4 dnia: 2009-03-23, 13:39:05 »
Dla wygody warto by przestawić ten opcjonalny na koniec, czyli jako trzeci, albo użyć getopts (patrz man bash).
Cytat: man bash
${parametr:+słowo}
       Używa wartości alternatywnej. Jeżeli parametr jest nieustawiony lub pusty, to nic nie jest podstawiane, w przeciwnym razie podstawiane jest zinterpretowane słowo.
W takim razie:
#!/bin/bash
WIERSZ=${3:+'NR=='$3}
eval "$1" | awk ${WIERSZ}' {print $'$2'}'

kormikez

  • Gość
Prozaiczny problem - zlepić kilka zmiennych w jedno wywołanie
« Odpowiedź #5 dnia: 2009-03-23, 15:24:14 »
Bardzo eleganckie :)
Dzięki serdeczne!