Нет всего один awk
и несколько выпусков его. Существует много awk реализаций, которые у каждого есть несколько версий. Все Нельды имеют свой собственный набор инструментов, который они поддерживают внутренний и программное обеспечение, которое поставлется с одним Unix и которое использует те инструменты, обычно полагаются на тех, которые точной версией той самой реализации.
Если Вы начинаете заменять /usr/bin/awk
с GNU awk, как может быть загружен с http://gnu.org, затем Вы столкнетесь с проблемами.
Некоторые Нельды действительно упаковывают версии альтернативного или Бесплатного программного обеспечения некоторых стандартных утилит. Обычно они делают это путем установки их в другом месте (/opt/gnu
например, для инструментов GNU) или под другим именем (gawk
для GNU awk). Если не можно загрузить их как источник и создать их и установить их в другом месте или под другим именем вручную сами.
Однако Солярис, как известно, имеет очень старые и нестандартные версии некоторых утилит в /usr/bin
и сохраните современные / стандартные версии в другом месте.
Это имеет место awk. /usr/bin/awk
на Солярисе основан на исходном awk с 1979. awk переписали приблизительно 1988 и назвали nawk
. Все современные awk
реализации основаны на этом nawk
(поскольку это что POSIX awk
спецификация на основе).
На Солярисе, если Вы обновляете Ваш $PATH
помещать себя в среду стандарта/POSIX (который обычно включает помещение /usr/xpg4/bin
и/или /usr/xpg6/bin
в начале $PATH
), затем awk
будет стандартный. С другой стороны, можно звонить nawk
вместо awk
.
Это - то же для sh
, можно использовать /usr/xpg4/bin/sh
или ksh
.
В стандарте sh (то есть, нет /bin/sh
на Солярисе), можно также использовать
command -p awk
Убеждаться назвать портативный awk вместо старого.
Во-первых, как и для многих утилит, у вас будет проблема с именами файлов, начинающимися с -
. Находясь в:
sh -c 'inline sh script here' other args
Остальные аргументы передаются в встроенный скрипт sh
; с эквивалентом perl
,
perl -e 'inline perl script here' other args
Остальные аргументы сначала сканируются на предмет дополнительных опций для perl , а не для встроенного скрипта.Так, например, если в текущем каталоге есть файл с именем -eBEGIN {do something evil}
,
perl -ne 'inline perl script here;' *
(с или без -n
) сделает что-то злое.
Как и для других утилит, для этого можно использовать маркер конца параметров ( -
):
perl -ne 'inline perl script here;' -- *
Но даже в этом случае это все еще опасно, и это сводится к <>
оператор, используемый -n
/ -p
.
Проблема объясняется в документации perldoc perlop
.
Этот специальный оператор используется для чтения одной строки (одна запись, записи по умолчанию являются строками) ввода, где этот ввод поступает от каждого из аргументов, переданных по очереди в @ARGV
.
In:
perl -pe '' a b
-p
подразумевает while (<>)
цикл вокруг кода (здесь пусто).
<>
сначала откроет a
, прочитает записи по одной строке, пока файл не будет исчерпан, а затем откроет b
...
Проблема в что для открытия файла используется первая небезопасная форма open
:
open ARGV, "the file as provided"
В этой форме, если аргумент
«> файл»
, открывается файл
в режиме записи, «cmd |»
, он запускает cmd
и считывает его вывод. "| cmd"
, у вас открыт поток для записи на вход cmd
. Так, например:
perl -pe '' 'uname|'
Выводит не содержимое файла с именем uname |
(вполне допустимое имя файла, кстати), а вывод команды uname
.
Если вы работаете:
perl -ne 'something' -- *
И кто-то создал файл с именем rm -rf "$ HOME" |
(опять же совершенно правильное имя файла) в текущем каталоге (например, потому что это каталог был когда-то доступен для записи другим, или вы извлекли хитрый архив, или вы выполнили какую-то хитрую команду, или другая уязвимость в каком-то другом программном обеспечении была использована), тогда у вас большие проблемы. Области, в которых важно знать об этой проблеме, - это инструменты, автоматически обрабатывающие файлы в общедоступных областях, таких как / tmp
(или инструменты, которые могут быть вызваны такими инструментами).
Файлы с именами > foo
, foo |
, | foo
представляют собой проблему. Но в меньшей степени
foo
с начальными или конечными символами пробела ASCII (включая пробел, табуляцию, новую строку, cr ...), а также это означает, что эти файлы выиграли ' не будет обработан, иначе будет неправильный.
Также обратите внимание, что некоторые символы в некоторых наборах многобайтовых символов (например, ǖ
в BIG5-HKSCS) заканчиваются байтом 0x7c, кодировкой |
.
$ printf ǖ | iconv -t BIG5-HKSCS | od -tx1 -tc
0000000 88 7c
210 |
0000002
Таким образом, в локали, использующей эту кодировку,
perl -pe '' ./nǖ
будет пытаться выполнить команду ./ n \ x88
как perl
, не будет пытаться интерпретировать это имя файла в локали пользователя!
AFAIK, вы ничего не можете сделать, чтобы изменить это небезопасное поведение по умолчанию perl
раз и навсегда во всей системе.
Во-первых, проблема возникает только с символами в начале и конце имени файла.Итак, хотя perl -ne '' *
или perl -ne '' * .txt
представляют собой проблему,
perl -ne 'some code' ./*.txt
не является проблемой, потому что все аргументы теперь начинаются с . /
и заканчиваются на .txt
(но не на -
, <
,>
, |
, пробел ...). В более общем плане рекомендуется использовать префикс globs с помощью ./
. Это также позволяет избежать проблем с файлами, называемыми -
или начинающимися с -
, со многими другими утилитами (и здесь это означает, что вам не нужны параметры конца ( - -
) маркер больше нет).
Использование -T
для включения режима taint
в некоторой степени помогает. Команда прервет команду, если обнаружится такой вредоносный файл (только для случаев >
и |
, но не <
или пробелов).
Это полезно при использовании таких команд в интерактивном режиме, поскольку предупреждает вас о том, что происходит что-то хитрое. Однако это может быть нежелательно при выполнении некоторой автоматической обработки, поскольку это означает, что кто-то может заставить эту обработку выйти из строя, просто создав файл.
Если вы хотите обрабатывать каждый файл, независимо от его имени, вы можете использовать модуль ARGV :: readonly
perl
на CPAN (к сожалению, обычно не устанавливается По умолчанию). Это очень короткий модуль, который выполняет:
sub import { # Tom Christiansen in Message-ID: <24692.1217339882@chthon> # по существу рекомендует следующее: для ( @ARGV) { s / ^ (\ s +) /.\/$ 1 /; # сохранены начальные пробелы s / ^ / ; # принудительно открыть для ввода $ _. = qq / \ 0 /; # завершающие пробелы сохранены и каналы запрещены }; };
По сути, он санирует @ARGV, превращая "foo |"
, например, в "<./ foo | \ 0"
.
Вы можете сделать то же самое в операторе BEGIN
в вашей команде perl -n / -p
:
perl -pe 'BEGIN{$_.="\0" for @ARGV} your code here' ./*
Здесь мы упрощаем его, предполагая, что ./
уже используется.
Побочным эффектом этого (и ARGV :: readonly
) является то, что $ ARGV
в ваш код здесь
показывает этот завершающий символ NUL.
perl
v5.21.5 и выше содержит новый оператор << >>
, который ведет себя как <>
, за исключением того, что он не выполняют эту специальную обработку. Аргументы будут рассматриваться только как имена файлов. Таким образом, с этими версиями теперь вы можете написать:
perl -e 'while(<<>>){ ...;}' -- *
(не забудьте -
или использовать ./*
), не опасаясь перезаписи файлов или выполнения неожиданных команд. .
-n
/ -p
по-прежнему используют опасную форму <>
. И будьте осторожны, символические ссылки все еще отслеживаются, так что это не обязательно означает, что их безопасно использовать в ненадежных каталогах.
@В дополнение к @Ответу Стефана Шазеляса, нам не нужно беспокоиться по этому поводу, если мы используем опцию командной строки -i
:
$ perl -pe '' 'uname|'
Linux
$ perl -i -pe '' 'uname|'
Can't open uname|: No such file or directory.
Поскольку при использовании опции -i
, perl
использовали stat для проверки состояния файла перед его обработкой:
$ strace -fe trace=stat perl -pe '' 'uname|'
stat("/home/cuonglm/perl5/lib/perl5/5.20.1/x86_64-linux", 0x7fffd44dff90) = -1 ENOENT (No such file or directory)
stat("/home/cuonglm/perl5/lib/perl5/5.20.1", 0x7fffd44dff90) = -1 ENOENT (No such file or directory)
stat("/home/cuonglm/perl5/lib/perl5/x86_64-linux", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
Process 6106 attached
Linux
Process 6105 suspended
Process 6105 resumed
Process 6106 detached
--- SIGCHLD (Child exited) @ 0 (0) ---
$ strace -fe trace=stat perl -i -pe '' 'uname|'
stat("/home/cuonglm/perl5/lib/perl5/5.20.1/x86_64-linux", 0x7fffdbaf2e50) = -1 ENOENT (No such file or directory)
stat("/home/cuonglm/perl5/lib/perl5/5.20.1", 0x7fffdbaf2e50) = -1 ENOENT (No such file or directory)
stat("/home/cuonglm/perl5/lib/perl5/x86_64-linux", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
stat("uname|", 0x785f40) = -1 ENOENT (No such file or directory)
Can't open uname|: No such file or directory.