Як надрукувати власне ім'я сценарію у mawk?


13

У bash $0міститься назва сценарію, але в розгортанні, якщо я роблю сценарій на ім'я myscript.awk із наступним вмістом:

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

і запустіть його, він буде друкувати лише "awk". Крім того, ARGV [i] з i> 0 використовується лише для аргументів сценарію в командному рядку. Отже, як змусити його надрукувати назву сценарію, в цьому випадку "myscript.awk"?


Я змінив назву з awk на mawk, тому що всі рішення потребують gawk і не працюють із загальним awk, і, зокрема, з mawk, який широко використовується (наприклад, за замовчуванням на Ubuntu)
cipper

Чому ви вважаєте mawk, що Ubuntu є типовим для Ubuntu? У моєму 15.04 ВМ за замовчуванням awkє gawk. Хоча mawk встановлений, він не є типовим.
terdon

1
Це сценарій awk, якщо ви його подзвоните awk -f myscript.awk. Однак це не пов'язано з проблемою, про яку йдеться.
шипшина

1
@EdMorton Це awkсценарій, оскільки він починається з #!/usr/bin/awk -f. Сценарії оболонки починаються з #!/bin/sh(або чогось подібного).
Бармар

1
Я спілкувався з різними експертами оболонки і намагаюся отримати остаточну відповідь на те, чи це сценарій оболонки або awk, і дивно, згідно з POSIX інтерпретація файлів, що починаються з #! не визначено і не має конкретного імені типу. Хоча деякі люди посилаються на це як на "інтерпретатор хеш-баг-інтерпретатора", а не на скрипт оболонки чи awk, схоже, що це вважається, що це слід вважати скриптом awk, навіть якщо ядро ​​(а не оболонка) інтерпретує перший рядок, оскільки awk досі має також мати можливість проаналізувати цей перший рядок (як коментар), і ви можете виконати його за допомогою awk -f file.
Ед Мортон

Відповіді:


5

З GNU awk 4.1.3 в bash на cygwin:

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

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

Я не знаю, наскільки це портативно. Як завжди, я б не виконував сценарій awk, використовуючи shebang в сценарії оболонки, оскільки він просто позбавляє вас можливої ​​функціональності. Зробіть це просто та просто зробіть це замість цього:

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

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

Цей останній буде працювати з будь-яким сучасним awk у будь-якій оболонці на будь-якій платформі.


Зауважте, що перший працює лише в bash, zsh або ksh. Пізніше йдеться про скрипт оболонки, а не про скрипт.
cuonglm

2
Дякую! ENVIRON["_"]працює чудово, і це не викликає жодної зовнішньої програми. Другий варіант awk -v ...залежить від способу запуску сценарію; Я цього не хочу.
шипшина

1
Виклик сценарію tst.shвводить в оману. Це awkсценарій, а не сценарій оболонки. BEGINне є дійсною командою оболонки.
Бармар

1
Правильно, але питання переносимості не є "чи ENVIRON [] портативний", це "чи ENVIRON["_"]виробляє шлях сценарію оболонки виклику, коли друкується з кожного каналу, що викликається через shebang з кожної оболонки"? Я б ніколи не закликав сценарій awk від shebang, щоб я особисто не переймався відповіддю, але просто думав, що це згадаю .... О, я бачу в коментарях вище, що @cuonglm відповів, що підтримується лише в деяких оболонках .
Ед Мортон

1
Хороший момент, @Ed. Перевірено як провал у тире (що повертає попередню команду (або ще й саму оболонку), а не поточну). ksh93 цікаво префіксує PID у зірочках, наприклад *12345*/tmp/test.awk. ARGV[0]надійно завжди awkв тире, bash, zsh та ksh93.
Адам Кац

5

Я не думаю, що це можливо згідно gawk документації :

Нарешті, значення ARGV[0](див. Розділ 7.5 Вбудовані змінні) змінюється залежно від вашої операційної системи. Деякі системи поміщають awkтуди, деякі ставлять повне ім'я awk (наприклад, /bin/awk), а деякі ставлять назву вашого сценарію ("рада"). Не покладайтеся на значення, ARGV[0]щоб вказати своє ім'я сценарію.

На linuxвас може спробувати використовувати вид брудний хака і як зазначено в коментарях Stéphane Chazelas це можливо , якщо реалізація awkопора NUL байт:

#!/usr/bin/awk -f

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

ваш сценарій, як здається, не працює. Він просто друкує "k", якщо його називають "awk -f script.awk", і він друкує "s", якщо його викликає "./script.awk"
cipper

@cipper: Тут він працює gawkі не працює (як ваш опис) mawk. Цікаво!

Він працює для мене в Linux, awk- 4.0.2. У Freebsd з /proc/curpoc/cmdline, а awkрезультат такий, як ваш, але працює з gawk.
taliezin

За замовчуванням ubuntu він не працює. Було б непогано знайти портативне рішення.
шипшина

1
@taliezin: відповідь cuonglm не є рішенням, оскільки йому потрібно вручну подати скрипт зі своїм ім'ям. Це як дзвонити, awk -vNAME="myscript.awk" ./myscript.awkа потім надрукувати NAME всередині сценарію. Не рішення.
шипшина

5

Я не знаю жодного прямого способу отримання імені команди зсередини awk. Однак ви можете знайти його через підрозділ.

гаук

За допомогою GNU awk та psкоманди ви можете використовувати ідентифікатор процесу з, PROCINFO["PID"]щоб отримати ім'я команди як вирішення. Наприклад:

cmdname.awk

#!/usr/bin/gawk -f

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

мавк і навк

Ви можете використовувати той самий підхід, але вивести awkPID зі $PPIDспеціальної змінної оболонки (PID батьків):

cmdname.awk

#!/usr/bin/mawk -f

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

Тестування

Запустіть сценарій так:

./cmdname.awk

Вихід у обох випадках:

cmdname.awk

Я отримав помилку: / bin / sh: 1: -o: не знайдено
cipper

@cipper: Це працює лише з GNU awk, я додав відсутню лінію shebang.
Тор

З посібника з gawk : Відповідно до POSIX, вираз | getline 'неоднозначний, якщо вираз містить нечітко визначені оператори, окрім' $ '- наприклад,' "echo" "date" | getline 'неоднозначний, оскільки оператор конкатенації не є скобками. Ви повинні записати це як '("відлуння" "дата") | getline ', якщо ви хочете, щоб ваша програма була портативною для всіх програм awk.
шипшина

1
Якщо це потрібно, gawkце gawkрішення, а не awkрішення. Я думаю, що @cipper повинен додати своє бажання "портативного рішення" до питання.

1
@Thor: відповідь cuonglm не є рішенням, оскільки йому потрібно вручну подати скрипт зі своїм ім'ям. Це як дзвонити, awk -vNAME="myscript.awk" ./myscript.awkа потім надрукувати NAME всередині сценарію. Не рішення.
шипшина

4

З POSIX awk:

#!/usr/bin/awk -f

BEGIN {
    print ENVIRON["AWKSCRIPT"]
}

Потім:

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


@cipper: Ну, це найпростіший і портативний спосіб, який я можу собі уявити.
cuonglm

3
Це як зателефонувати, awk -vNAME="myscript.awk" ./myscript.awkа потім надрукувати змінну NAMEвсередині сценарію. Не рішення.
шипшина

@cipper: Це єдиний спосіб, якщо ви згадаєте mawk. А також використання ENVIRONне те саме, що використання -vNAME="myscript.awk", оскільки коли mawkбуде розгорнута послідовність втечі в NAME.
cuonglm

4

Використання GNU awk

Перевірка посібника користувача GNU awk - 7.5.2 Вбудовані змінні, що передають інформацію, на яку я натрапив:

ПРОЦІНФО №

Елементи цього масиву забезпечують доступ до інформації про запущену програму awk. Наступні елементи (перелічені в алфавітному порядку) гарантовано доступні:

PROCINFO ["pid"]

Ідентифікатор процесу поточного процесу.

Це означає, що ви можете знати PID програми під час виконання. Потім system()слід шукати процес із цим заданим PID:

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

Я використовую ps -ef, що відображає PID на 2-му стовпці. Припускаючи, що виконанняg виконується за допомогою awk -f <script>інших параметрів, і немає інших параметрів, ми можемо вважати, що останнє поле рядка містить потрібну нам інформацію.

У випадку, якщо у нас були деякі параметри, нам доведеться розбирати рядок інакше - або, краще, скористайтеся деякими з варіантів, psщоб надрукувати лише ті колонки, які нас цікавлять.

Тест

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

Зауважте також, що ще одна глава керівництва користувача GNU awk говорить нам, що ARGV - це не такий шлях:

1.1.4 Виконані програми awk

Нарешті, значення ARGV [0] (див. Вбудовані змінні) змінюється залежно від вашої операційної системи. Деякі системи ставлять туди "awk", деякі ставлять повне ім'я awk (наприклад, / bin / awk), а деякі ставлять назву вашого сценарію ("рада"). (dc) Не покладайтеся на значення ARGV [0], щоб вказати своє ім'я сценарію.


на жаль, PROCINFO - це лише функція gawk, а не загальна жахливість. Наприклад, він недоступний у mawk (який встановлено за замовчуванням в ubuntu)
шифр

Я знаю ... Чому ви позначили це питання тоді [gawk]?
fedorqui

Ти маєш рацію. Коли я опублікував питання, я не знав про всі ці відмінності між mawk і gawk. Тег змінився на mawk зараз.
шипшина

@cipper добре:) Я насправді тестував mawkі не міг змусити його працювати, так що я встановив gawkу себе Ubuntu, і він працював. Тож можна gawk
подолати

1
@terdon, gawkне встановлено за замовчуванням на Ubuntu (або принаймні деякі версії Ubuntu, де реалізація mawkза замовчуванням awk). IIRC, мені довелося встановити його також на Debian.
Стефан Шазелас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.