Jak wydrukować własną nazwę skryptu w mawk?


13

W bash $0zawiera nazwę skryptu, ale w awk, jeśli utworzę skrypt o nazwie myscript.awk o następującej treści:

#!/usr/bin/awk -f
BEGIN{ print ARGV[0] }

i uruchom go, wypisze tylko „awk”. Poza tym ARGV [i] z i> 0 służy tylko do argumentów skryptu w wierszu poleceń. Jak więc wydrukować nazwę skryptu, w tym przypadku „myscript.awk”?


Zmieniłem tytuł z awk na mawk, ponieważ wszystkie rozwiązania wymagają gawk i nie działają z ogólnym awk, aw szczególności z powszechnie używanym mawk (np. Domyślnym w Ubuntu)
cipper

Co sprawia, że ​​uważasz, że mawkjest domyślny w Ubuntu? Na mojej maszynie wirtualnej 15.04 domyślną wartością awkjest gawk. Podczas gdy mawk jest zainstalowany, nie jest domyślny.
terdon

1
Jest to skrypt awk, jeśli go nazwiesz awk -f myscript.awk. Nie ma to jednak związku z omawianym problemem.
cipper

1
@EdMorton To awkskrypt, ponieważ zaczyna się od #!/usr/bin/awk -f. Skrypty powłoki zaczynają się od #!/bin/sh(lub czegoś podobnego).
Barmar

1
Rozmawiałem z różnymi ekspertami od powłoki i starałem się uzyskać ostateczną odpowiedź na temat tego, czy jest to skrypt powłoki czy awk i, co zaskakujące, zgodnie z POSIX, interpretacja plików zaczynających się od #! jest niezdefiniowany i nie ma określonej nazwy typu. Chociaż niektórzy nazywają go „skryptem interpretera skrótu”, a nie skryptem powłoki lub awk, wydaje się, że należy uznać, że należy go traktować jako skrypt awk, mimo że jądro (nie powłoka) interpretuje pierwszą linię, ponieważ awk wciąż musi być w stanie przeanalizować również ten pierwszy wiersz (jako komentarz) i można go wykonać za pomocą awk -f file.
Ed Morton,

Odpowiedzi:


5

Z GNU awk 4.1.3 w bash na cygwin:

$ cat tst.sh
#!/bin/awk -f
BEGIN { print "Executing:", ENVIRON["_"] }

$ ./tst.sh
Executing: ./tst.sh

Nie wiem, jak to jest przenośne. Jak zawsze jednak nie wykonałbym skryptu awk za pomocą shebang w skrypcie powłoki, ponieważ po prostu okrada cię z możliwej funkcjonalności. Uprość to i po prostu zrób to zamiast tego:

$ cat tst2.sh
awk -v cmd="$0" '
BEGIN { print "Executing:", cmd }
' "$@"

$ ./tst2.sh
Executing: ./tst2.sh

To ostatnie będzie działać z każdym nowoczesnym awk w dowolnej powłoce na dowolnej platformie.


Zauważ, że pierwszy działa tylko w bash, zsh lub ksh. Później dotyczy skryptu powłoki, a nie skryptu awk.
cuonglm

2
Dziękuję Ci! ENVIRON["_"]działa idealnie i nie wywołuje żadnego programu zewnętrznego. Druga opcja awk -v ...zależy od sposobu uruchomienia skryptu; Nie chce tego
cipper

1
Wywołanie skryptu tst.shjest mylące. To awkskrypt, a nie skrypt powłoki. BEGINnie jest prawidłowym poleceniem powłoki.
Barmar

1
Zgadza się, ale pytanie dotyczące przenośności nie brzmi „czy ENVIRON [] jest przenośny”, „czy” ENVIRON["_"]generuje ścieżkę skryptu powłoki wywołującej, gdy jest drukowana z każdego awk wywoływanego przez shebang z każdej powłoki ”? Nigdy nie wywołałbym skryptu awk z shebang, ale osobiście nie dbam o odpowiedź, ale pomyślałem, że o tym wspomnę ... Och, widzę w komentarzach powyżej, że @cuonglm odpowiedział, że jest obsługiwany tylko w niektórych powłokach .
Ed Morton,

1
Dobra uwaga, @Ed. Zweryfikowano jako niepowodzenie w myślniku (który zwraca poprzednie polecenie (lub samą powłokę) zamiast bieżącego). ksh93 co ciekawe prefiks PID w gwiazdkach, np *12345*/tmp/test.awk. ARGV[0]jest niezawodnie zawsze awkw myślniku, bashu, zsh i ksh93.
Adam Katz

5

Nie sądzę, że jest to możliwe zgodnie z gawk dokumentacją :

Wreszcie, wartość ARGV[0](zob. 7.5. Zmienne wbudowane) różni się w zależności od systemu operacyjnego. Niektóre systemy awktam umieszczają , niektóre umieszczają pełną ścieżkę do awk (np. /bin/awk), A niektóre podają nazwę twojego skryptu („porady”). Nie polegaj na wartości, ARGV[0]aby podać nazwę skryptu.

Na linuxmożesz spróbować użyć pewnego rodzaju brudnego hacka i jak wskazano w komentarzach Stéphane Chazelas , możliwe jest, jeśli implementacja awkobsługuje bajty NUL:

#!/usr/bin/awk -f

BEGIN { getline t < "/proc/self/cmdline"; split(t, a, "\0"); print a[3]; }

Twój skrypt, jak się wydaje, nie działa. Po prostu wypisuje „k”, jeśli jest wywoływane za pomocą „awk -f script.awk”, i wypisuje „s”, jeśli jest wywoływane przez „./script.awk”
cipper

@cipper: Tutaj działa z gawki kończy się niepowodzeniem (jak twój opis) z mawk. Ciekawy!

Działa dla mnie w systemie Linux, awk- 4.0.2. W FreeBSD z /proc/curpoc/cmdline, a awkwynik jest jak twoje, ale działa z gawk.
taliezin

Domyślnie Ubuntu nie działa. Byłoby miło znaleźć przenośne rozwiązanie.
cipper

1
@taliezin: odpowiedź cuonglm nie jest rozwiązaniem, ponieważ wymaga ręcznego podania skryptu z jego nazwą. To tak, jakby zadzwonić, awk -vNAME="myscript.awk" ./myscript.awka następnie wydrukować NAME w skrypcie. Nie rozwiązanie.
cipper

5

Nie znam żadnego bezpośredniego sposobu uzyskania nazwy polecenia z poziomu awk. Można go jednak znaleźć w podpowłoce.

gapić się

Za pomocą GNU awk i pspolecenia możesz użyć identyfikatora procesu, PROCINFO["PID"]aby pobrać nazwę polecenia jako obejście. Na przykład:

cmdname.awk

#!/usr/bin/gawk -f

BEGIN {
  ("ps -p " PROCINFO["pid"] " -o comm=") | getline CMDNAME
  print CMDNAME
}

mawk i nawk

Możesz użyć tego samego podejścia, ale uzyskaj awkPID ze $PPIDspecjalnej zmiennej powłoki (PID rodzica):

cmdname.awk

#!/usr/bin/mawk -f

BEGIN { 
  ("ps -p $PPID -o comm=") | getline CMDNAME
  print CMDNAME
}

Testowanie

Uruchom skrypt w następujący sposób:

./cmdname.awk

Dane wyjściowe w obu przypadkach:

cmdname.awk


@cipper: Działa to tylko z GNU awk, dodałem brakującą linię shebang.
Thor

Z podręcznika gawk : Według POSIX „wyrażenie | getline ”jest dwuznaczny, jeśli wyrażenie zawiera niepodzielne operatory inne niż„ $ ”- na przykład„ echo ”„ data ”| getline ”jest niejednoznaczny, ponieważ operator konkatenacji nie jest nawiasowany. Powinieneś napisać to jako „(„ echo ”„ data ”) | getline ', jeśli chcesz, aby Twój program był przenośny dla wszystkich implementacji awk.
cipper

1
Jeśli to gawkkonieczne, jest to gawkrozwiązanie zamiast awkrozwiązania. Myślę, że @cipper powinien dodać swoje pytanie „przenośne rozwiązanie” do pytania.

1
@Thor: odpowiedź cuonglm nie jest rozwiązaniem, ponieważ wymaga ręcznego podania skryptu z jego nazwą. To tak, jakby zadzwonić, awk -vNAME="myscript.awk" ./myscript.awka następnie wydrukować NAME w skrypcie. Nie rozwiązanie.
cipper

4

Z POSIX awk:

#!/usr/bin/awk -f

BEGIN {
    print ENVIRON["AWKSCRIPT"]
}

Następnie:

AWKSCRIPT=test.awk ./test.awk
test.awk

5
Ręcznie
podajesz

@cipper: Cóż, to najłatwiejszy i najbardziej przenośny sposób, jaki mogę sobie wyobrazić.
cuonglm

3
To jest jak wywołanie, awk -vNAME="myscript.awk" ./myscript.awka następnie wydrukowanie zmiennej NAMEw skrypcie. Nie rozwiązanie.
cipper

@cipper: To jedyny sposób, jeśli wspomniasz mawk. A także używanie ENVIRONnie jest tym samym, co używanie -vNAME="myscript.awk", ponieważ kiedy mawkrozwinie sekwencję zmiany znaczenia w NAME.
cuonglm

4

Korzystanie z GNU awk

Sprawdzanie podręcznika użytkownika GNU awk - 7.5.2 Wbudowane zmienne, które przekazują informacje Natknąłem się na:

PROCINFO #

Elementy tej tablicy zapewniają dostęp do informacji o działającym programie awk. Zapewnione są następujące elementy (wymienione alfabetycznie):

PROCINFO [„pid”]

Identyfikator bieżącego procesu.

Oznacza to, że możesz znać PID programu podczas działania. Następnie system()należy poszukać procesu z tym danym PID:

#!/usr/bin/gawk -f
BEGIN{ pid=PROCINFO["pid"]
       system("ps -ef | awk '$2==" pid " {print $NF}'")
}

Używam ps -ef, który wyświetla PID w drugiej kolumnie. Zakładając, że wykonanie zostało wykonane awk -f <script>bez żadnych innych parametrów, możemy założyć, że ostatnie pole wiersza zawiera potrzebne informacje.

Gdybyśmy mieli jakieś parametry, musielibyśmy przeanalizować wiersz inaczej - lub, lepiej, skorzystać z niektórych opcji psdrukowania tylko interesujących nas kolumn.

Test

$ awk -f a.awk 
a.awk
$ cp a.awk hello.awk
$ awk -f hello.awk 
hello.awk

Zauważ również, że kolejny rozdział podręcznika użytkownika GNU awk mówi nam, że ARGV nie jest właściwą drogą:

1.1.4 Wykonywalne programy awk

Wreszcie wartość ARGV [0] (patrz Zmienne wbudowane) różni się w zależności od systemu operacyjnego. Niektóre systemy umieszczają tam słowo „awk”, niektóre umieszczają pełną ścieżkę do pliku awk (np. / Bin / awk), a niektóre podają nazwę skryptu („rada”). (dc) Nie polegaj na wartości ARGV [0], aby podać nazwę skryptu.


niestety PROCINFO to tylko funkcja gawk, a nie ogólny awk. Na przykład nie jest dostępny w mawk (który jest domyślnie instalowany w Ubuntu)
cipper

Wiem ... Dlaczego otagowałeś pytanie [gawk]?
fedorqui

Masz rację. Kiedy opublikowałem pytanie, nie wiedziałem o tych wszystkich różnicach między mawk a gawk. Tag zmienił się teraz na mawk.
cipper

@cipper good:) W rzeczywistości testowałem mawki nie mogłem sprawić, aby działał, więc zainstalowałem gawkw moim Ubuntu i działało. Można więc zastosować obejście gawk: D
fedorqui

1
@terdon, gawknie jest domyślnie instalowany na Ubuntu (lub przynajmniej niektórych wersjach Ubuntu, gdzie mawkjest domyślną awkimplementacją). IIRC, musiałem również zainstalować go na Debianie.
Stéphane Chazelas,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.