Текущий каталог (т.е. .
) не находится в Вашем пути. Попробуйте
./startup.sh
Можно проверить путь с
echo ${PATH}
Вы могли добавить текущий каталог (.
) к Вашему пути, но это считают риском (особенно, если .
перед другими каталогами): при вводе команды оболочка сначала попытается выполнить его в текущем каталоге. Это выполнит то, что там вместо по умолчанию.
Суммирование: только запустите исполняемые файлы в текущем каталоге с ./
перед ними.
Конструкция <(tac file)
заставляет оболочку:
/ dev / fd
, используется обычный канал, а / dev / fd / <дескриптор-файла-канала >
используется как имя. tac-файл
и подключите его к одному концу трубы. После замены командная строка становится такой:
grep whatever < /tmp/whatever-name-the-shell-used-for-the-named-pipe
И затем выполняется grep
, и он считывает свой стандартный ввод (который является каналом), читает его и ищет свой первый аргумент в который.
Таким образом, конечный результат такой же, как и с ...
tac file | grep whatever
... в том, что запускаются те же две программы, и для их соединения по-прежнему используется канал. Но конструкция <(...)
более запутанная, потому что она включает больше шагов и может включать временный файл (именованный канал).
Конструкция <(...)
является расширением и недоступна в стандартной оболочке POSIX bourne или на платформах, не поддерживающих / dev / fd
или именованных трубы. Только по этой причине, поскольку две рассматриваемые альтернативы в точности эквивалентны по функциональности, команда more portable | Форма other-command
- лучший выбор.
Конструкция <(...)
должна быть медленнее из-за дополнительной свертки, но это только на этапе запуска, и я не думаю, что разницу будет легко измерить.
ПРИМЕЧАНИЕ : На платформах Linux SysV <(...)
не использует именованные каналы, а вместо этого использует обычные каналы. Обычные каналы (действительно, все файловые дескрипторы) могут упоминаться по специальному имени / dev / fd / <номер-дескриптора файла
, так что это то, что оболочка использует в качестве имени канала. Таким образом, он избегает создания реального именованного канала с истинным временным именем файла в реальной файловой системе. Хотя трюк / dev / fd
- это то, что использовалось для реализации этой функции, когда она изначально появилась в ksh
, это оптимизация: на платформах, которые не поддерживают это, обычная именованный канал в реальной файловой системе используется, как описано выше.
ТАКЖЕ ПРИМЕЧАНИЕ : описание синтаксиса как << (...)
вводит в заблуждение. На самом деле это <(...)
, которое заменяется именем канала, а затем другой символ <
, который ставит префикс всего этого, отделен от этого синтаксиса, и это обычный хорошо известный синтаксис для перенаправления ввода из файла.
В чем разница между | и << ()?
Между ними есть разница:
|
вызывают выполнение каждой команды в отдельной подоболочке.
<()
запустить команду, которая подставляется в фоновый режим.
Для следующих двух вопросов мы сделаем несколько strace
:
pipe
:
$ strace -fc bash -c 'tac /usr/share/dict/american-english | grep qwerty'
$ time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
100.00 0.008120 2707 3 1 wait4
0.00 0.000000 0 352 read
0.00 0.000000 0 229 write
0.00 0.000000 0 20 2 open
0.00 0.000000 0 29 2 close
0.00 0.000000 0 40 17 stat
0.00 0.000000 0 19 fstat
0.00 0.000000 0 117 lseek
0.00 0.000000 0 38 mmap
0.00 0.000000 0 18 mprotect
0.00 0.000000 0 6 munmap
0.00 0.000000 0 25 brk
0.00 0.000000 0 22 rt_sigaction
0.00 0.000000 0 18 rt_sigprocmask
0.00 0.000000 0 1 rt_sigreturn
0.00 0.000000 0 3 2 ioctl
0.00 0.000000 0 24 12 access
0.00 0.000000 0 1 pipe
0.00 0.000000 0 2 dup2
0.00 0.000000 0 1 getpid
0.00 0.000000 0 1 1 getpeername
0.00 0.000000 0 2 clone
0.00 0.000000 0 3 execve
0.00 0.000000 0 1 uname
0.00 0.000000 0 1 getrlimit
0.00 0.000000 0 13 getuid
0.00 0.000000 0 13 getgid
0.00 0.000000 0 13 geteuid
0.00 0.000000 0 13 getegid
0.00 0.000000 0 1 getppid
0.00 0.000000 0 1 getpgrp
0.00 0.000000 0 3 arch_prctl
0.00 0.000000 0 1 time
------ ----------- ----------- --------- --------- ----------------
100.00 0.008120 1034 37 total
Process Substitution
:
$ strace -fc bash -c 'grep qwerty < <(tac /usr/share/dict/american-english)'
$ time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
99.14 0.016001 4000 4 2 wait4
0.46 0.000075 0 229 write
0.24 0.000038 0 341 read
0.16 0.000026 1 24 brk
0.00 0.000000 0 21 2 open
0.00 0.000000 0 27 close
0.00 0.000000 0 40 17 stat
0.00 0.000000 0 19 fstat
0.00 0.000000 0 117 lseek
0.00 0.000000 0 38 mmap
0.00 0.000000 0 18 mprotect
0.00 0.000000 0 6 munmap
0.00 0.000000 0 35 rt_sigaction
0.00 0.000000 0 24 rt_sigprocmask
0.00 0.000000 0 2 rt_sigreturn
0.00 0.000000 0 3 2 ioctl
0.00 0.000000 0 24 12 access
0.00 0.000000 0 1 pipe
0.00 0.000000 0 3 dup2
0.00 0.000000 0 1 getpid
0.00 0.000000 0 1 1 getpeername
0.00 0.000000 0 3 clone
0.00 0.000000 0 3 execve
0.00 0.000000 0 1 uname
0.00 0.000000 0 1 1 fcntl
0.00 0.000000 0 2 getrlimit
0.00 0.000000 0 13 getuid
0.00 0.000000 0 13 getgid
0.00 0.000000 0 13 geteuid
0.00 0.000000 0 13 getegid
0.00 0.000000 0 1 getppid
0.00 0.000000 0 1 getpgrp
0.00 0.000000 0 3 arch_prctl
0.00 0.000000 0 1 time
------ ----------- ----------- --------- --------- ----------------
100.00 0.016140 1046 37 total
Почему что-то быстрее, чем другое?
А что на самом деле быстрее?
Как видите, подстановка процесса
в этом случае медленнее, чем pipe
, потому что она использует больше системных вызовов. Оба тратят много времени на ожидание дочерних процессов, но подстановка процесса
использует больше системного вызова wait4 ()
и использует больше времени для каждого вызова, чем pipe
.
Почему никто не предлагает xargs?
Я не думаю, что xargs
может здесь чем-то помочь, это не его работа.
Обновление
Как предложил @ Gilles, я провожу тест с большим файлом, 2 ГБ случайных данных, сгенерированных из / dev / urandom
. Это показывает, что pipe
действительно быстрее, чем замещение процесса
.
труба
:
$ strace -fc bash -c 'tac sample.txt | grep qwerty'
$ time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
81.15 8.284959 2761653 3 1 wait4
17.89 1.825959 2 780959 read
0.91 0.092708 0 524286 write
0.05 0.005364 0 262146 lseek
0.00 0.000000 0 20 2 open
0.00 0.000000 0 29 2 close
0.00 0.000000 0 40 17 stat
0.00 0.000000 0 19 fstat
0.00 0.000000 0 38 mmap
0.00 0.000000 0 18 mprotect
0.00 0.000000 0 6 munmap
0.00 0.000000 0 25 brk
0.00 0.000000 0 22 rt_sigaction
0.00 0.000000 0 18 rt_sigprocmask
0.00 0.000000 0 1 rt_sigreturn
0.00 0.000000 0 3 2 ioctl
0.00 0.000000 0 24 12 access
0.00 0.000000 0 1 pipe
0.00 0.000000 0 2 dup2
0.00 0.000000 0 1 getpid
0.00 0.000000 0 1 1 getpeername
0.00 0.000000 0 2 clone
0.00 0.000000 0 3 execve
0.00 0.000000 0 1 uname
0.00 0.000000 0 1 getrlimit
0.00 0.000000 0 13 getuid
0.00 0.000000 0 13 getgid
0.00 0.000000 0 13 geteuid
0.00 0.000000 0 13 getegid
0.00 0.000000 0 1 getppid
0.00 0.000000 0 1 getpgrp
0.00 0.000000 0 3 arch_prctl
0.00 0.000000 0 1 time
------ ----------- ----------- --------- --------- ----------------
100.00 10.208990 1567727 37 total
подстановка процесса
:
$ strace -fc bash -c 'grep qwerty < <(tac sample.txt)'
$ time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
99.51 13.912869 3478217 4 2 wait4
0.38 0.053373 0 655269 read
0.09 0.013084 0 524286 write
0.02 0.002454 0 262146 lseek
0.00 0.000030 1 38 mmap
0.00 0.000024 1 24 12 access
0.00 0.000000 0 21 2 open
0.00 0.000000 0 27 close
0.00 0.000000 0 40 17 stat
0.00 0.000000 0 19 fstat
0.00 0.000000 0 18 mprotect
0.00 0.000000 0 6 munmap
0.00 0.000000 0 24 brk
0.00 0.000000 0 35 rt_sigaction
0.00 0.000000 0 24 rt_sigprocmask
0.00 0.000000 0 2 rt_sigreturn
0.00 0.000000 0 3 2 ioctl
0.00 0.000000 0 1 pipe
0.00 0.000000 0 3 dup2
0.00 0.000000 0 1 getpid
0.00 0.000000 0 1 1 getpeername
0.00 0.000000 0 3 clone
0.00 0.000000 0 3 execve
0.00 0.000000 0 1 uname
0.00 0.000000 0 1 1 fcntl
0.00 0.000000 0 2 getrlimit
0.00 0.000000 0 13 getuid
0.00 0.000000 0 13 getgid
0.00 0.000000 0 13 geteuid
0.00 0.000000 0 13 getegid
0.00 0.000000 0 1 getppid
0.00 0.000000 0 1 getpgrp
0.00 0.000000 0 3 arch_prctl
0.00 0.000000 0 1 time
------ ----------- ----------- --------- --------- ----------------
100.00 13.981834 1442060 37 total
Мне не удалось воспроизвести результаты, показанные cuonglm . Даже с файлом размером 2 ГБ в Bash 5 на MacOS Mojave я вижу очень похожие тайминги между заменой процесса и каналом. Это имеет смысл для меня, так как накладные расходы, связанные с вызовом, будут минимальными по сравнению с фактической обработкой этого вызова для файла размером 2 ГБ, поэтому выполнение одной итерации использования подстановки процесса вместо канала будет отключено. к случайности / какая команда была запущена первой для кэширования содержимого файла.
Мне удалось воспроизвести выводы в этом вопросе , которые показывают, что подстановка процессов выполняется быстрее, чем конвейеры при нескольких тысячах вызовов.
Вот команды, которые я выполнил, и вывод:
труб.ш:
shopt -s lastpipe
for i in {1..5000}; do
echo foo bar |
while read; do
echo $REPLY >/dev/null
done
done
проц -под.ш:
for i in {1..5000}; do
while read; do
echo $REPLY >/dev/null
done < <(echo foo bar)
done
труба -нет -ластпайп.ш:
for i in {1..5000}; do
echo foo bar |
while read; do
echo $REPLY >/dev/null
done
done
Тест:
time./proc-sub.sh
real 0m9.505s
user 0m1.875s
sys 0m10.705s
time./pipe.sh
real 0m14.036s
user 0m4.583s
sys 0m14.193s
time./pipe-no-lastpipe.sh
real 0m16.696s
user 0m3.055s
sys 0m18.057s