Попробуйте это
awk '
NR==1 {
print;
next;
}
NR==FNR {
split($2,a,",");
for(i in a) b[a[i]] = b[a[i]]==""? $1 : b[a[i]] "," $1;
next;
}
{
if ($1 in b) print $1 "\t" b[$1];
}
' File1 File2
Если у вас нет / не нужна строка заголовка, вы можете упростить, отбросив первую пару правило / действие.
Это по той же причине, что и вам нужно написать:
rm -- *.txt
А не
rm *.txt
Если вы не можете гарантировать, что ни один из файлов .txt
в текущем каталоге не имеет имени, начинающегося с -
.
В:
rm <arg>
считается вариантом, если он начинается с -
или файла, который нужно удалить в противном случае. В
rm -- <arg>
arg
всегда рассматривается как файл для удаления, независимо от того, начинается он с -
или нет.
То же самое для sh
.
Когда выполняется сценарий, который начинается с
#! /bin/sh
Обычно с:
execve("path/to/the-script", ["the-script", "arg"], [environ])
Система преобразует его в:
execve("/bin/sh", ["/bin/sh", "path/to/the-script", "arg"], [environ])
Путь / к / сценарию
обычно не находится под контроль автора сценария. Автор не может предсказать, где и под каким именем будут храниться копии сценария. В частности, они не могут гарантировать, что путь / к / скрипту
, с которым он вызывается, не будет начинаться с -
(или +
, который также проблема с sh
). Вот почему нам нужны , -
здесь, чтобы отметить конец параметров.
Например, в моей системе zcat
(как и большинство других скриптов на самом деле) является одним из примеров скрипта, который не следовал этой рекомендации:
$ head -n1 /bin/zcat
#!/bin/sh
$ mkdir +
$ ln -s /bin/zcat +/
$ +/zcat
/bin/sh: +/: invalid option
[...]
Теперь вы можете спросить, почему #! / bin / sh -
, а не #! / bin / sh -
?
Хотя #! / bin / sh -
будет работать с оболочками POSIX, #! / bin / sh -
более портативен; в частности к древним версиям sh
. sh
обработка -
как предшественников конца опции getopt ()
и общее использование -
для обозначения конца варианты на долгое время. Так как оболочка Bourne (с конца 70-х) анализировала свои аргументы, только первый аргумент рассматривался для параметров, если он начинался с -
. Все символы после -
будут рассматриваться
как имена параметров; если после -
не было символа, вариантов не было. Это застряло, и все более поздние оболочки, подобные Борну, распознают -
как способ отметить конец параметров.
В оболочке Борна (но не в современных оболочках типа Борна) #! / bin / sh -euf
также поможет обойти проблему, поскольку для опций учитывался только первый аргумент.
Можно сказать, что мы здесь педантичны, и именно поэтому я написал потребность курсивом выше:
-
или +
или поместите их в каталог, имя которого начинается с -
или +
. execvp ()
/ функции типа execlp ()
.И в этом случае обычно вы вызываете их либо как the-script
, чтобы его можно было найти в $ PATH
, и в этом случае аргумент пути к execve ()
системный вызов обычно начинается с /
(не -
и +
) или как ./ the-script
, если вы хотите сценарий
в текущем каталоге, который будет запущен (а затем путь начинается с ./
, а не с -
или +
). Теперь, помимо проблемы теоретической правильности , есть еще одна причина, по которой #! / bin / sh -
был рекомендован в качестве хорошей практики . И это восходит к тому времени, когда несколько систем все еще поддерживали сценарии setuid.
Если у вас есть сценарий, содержащий:
#! /bin/sh
/bin/echo "I'm running as root"
И этот сценарий был установлен с идентификатором root (например, с разрешениями -r-sr-xr-x root bin
) в этих системах при выполнении обычный пользователь,
execve("/bin/sh", ["/bin/sh", "path/to/the-script"], [environ])
будет выполнен как root
!
Если пользователь создал символическую ссылку / tmp / -i -> путь / к / сценарию
и выполнил ее как -i
, то он запустил бы интерактивную оболочку ( / bin / sh -i
) как корень
.
-
может обойти это (это не будет работать с проблемой состояния гонки или того факта, что некоторые реализации sh
, такие как некоторые на основе] ksh88
будут искать аргументы скрипта без /
в $ PATH
).
В настоящее время практически никакая система не поддерживает сценарий setuid, а некоторые из тех, которые все еще поддерживают (обычно не по умолчанию), в конечном итоге выполняют execve ("/ bin / sh", ["/ bin / sh "," / dev / fd /
(где
- дескриптор файла, открытый для чтения в скрипте), который работает как с этой проблемой, так и с гонкой состояние.
Обратите внимание, что аналогичные проблемы возникают с большинством интерпретаторов, а не только с оболочками типа Борна. Не-Борн-подобные оболочки обычно не поддерживают -
в качестве маркера конца опции, но обычно поддерживают вместо него -
(по крайней мере, для современных версий).
Также
#! /usr/bin/awk -f
#! /usr/bin/sed -f
Нет проблемы, так как следующий аргумент в любом случае рассматривается как аргумент для параметра -f
, но он все равно не работает, если path / to / script
- это -
(в этом случае с большинством реализаций sed
/ awk
, sed
/ awk
считывает код не из файла -
, а из стандартного ввода).
Также обратите внимание, что в большинстве систем нельзя использовать:
#! /usr/bin/env sh -
#! /usr/bin/perl -w --
Как и в большинстве систем, механизм shebang допускает только один аргумент после пути интерпретатора.
Относительно использования #! / bin / sh -
vs #! / bin / sh -
, это дело вкуса. Я предпочитаю первый вариант, так как он делает путь интерпретатора более заметным и упрощает выбор мышью. Существует легенда , в которой говорится, что пространство необходимо в некоторых древних версиях Unix , но AFAIK, это никогда не проверялось.
Очень хорошую ссылку на Unix shebang можно найти на https://www.in-ulm.de/~mascheck/various/shebang