Прав доступа на выполнение достаточно, чтобы ядро могло выполнить файл.
Если файл начинается с #!
, тогда он увидит, что это скрипт, проанализирует эту строку, чтобы узнать путь интерпретатора и необязательный аргумент, а затем запустит этот интерпретатор с этим необязательным аргументом и путем к файлу в качестве аргумента.
Например, если файл начинается с:
#! /usr/bin/python -E
Ядро изменяет execve("/path/to/the-script", ["the-script", "arg"], [envs] )
to execve("/usr/bin/python", ["/usr/bin/python", "-E", "/path/to/the-script", "arg"], [окружение])
.
Без разрешения на выполнение это никогда бы не зашло так далеко.
Теперь, в этот момент, важно разрешение интерпретатора на выполнение. Это исполняемые файлы, тогда он работает как обычно.
Однако позже /usr/bin/python
захочет открыть /path/to/the-script
для чтения и интерпретации кода в нем. И для этого ему потребуется разрешение на чтение файла. Если, возможно, он не изменил euid с прошлого раза (например, если файл /usr/bin/python
имел бит suid/sgid), если у вас ранее не было прав на чтение, вы все равно не иметь это.
Таким образом, вы можете выполнить скрипт, если у вас есть только разрешение на его выполнение. Просто, если интерпретатору нужно открыть его, чтобы прочитать его содержимое, он терпит неудачу (и вы видите, что сообщение об ошибке исходит от интерпретатора, а не от оболочки, из которой вы пытаетесь запустить этот скрипт).В таком сценарии, как:
#! /bin/echo Here goes
Вы увидите, что отсутствие разрешения на чтение не имеет значения, так как echo
не пытается открыть файл для чтения.
Вы можете использовать параметр -c
команды grep. И вы можете удалить все символы до первой запятой и все, начиная со второй запятой, с помощью sed
:
sed 's/^[^,]*,//;s/,.*//' < the_file | grep -c -E '[^0]'
РЕДАКТИРОВАТЬ: Эта команда sed
делает то же самое, что и ваша cut
, поэтому вы также сможете использовать исходную команду grep
.
РЕДАКТИРОВАТЬ2: Если вы хотите использовать только одну команду, вы можете использовать ответ @cuonglm grp. Если вы хотите использовать только один вызов из sed
, потребуется много работы с метками, чтобы суммировать количество строк в конце.
sed -E -n '
s/^[^,]*,[^0,]+,.*/+1/ # replace the lines we are interested in with "+1"
T delete_line # if we did not do a substitution right now we jump to "delete_line"
H # we did not jump (so we did the substitution and append the "+1" to the hold space
: delete_line # the label, here we do nothing (silently drop the current line)
$ { # on the last line we ...
s/.*/0/ # replace the whole line with "0"
G # append the hold space (all the "+1" from before")
s/\n//g # remove all newlines
p # print the line
}' < the_file
Теперь это можно передать по конвейеру bc
, или вы можете заменить команду p
сложной магией sed
, чтобы суммировать эти числа в sed
. Кажется, я слышал, что sed
завершен по Тьюрингу, поэтому это должно быть возможно.
Если вы хотите использовать только одну программу ( sed
), но не хотите вызывать ее несколько раз, это намного проще:
sed '/^[^,]*,0,.*/d' < the_file | sed -n '$='
С grep
:
grep -c '^[^,]*,[^0]' <file
Это работает, только если 2-й столбец сформирован как целое число, но не -0
, +0
. Для более общего случая см. @ Ответ Стефана Хазеласа .
grep -c '^[^,]*,[-+0-9.]*[1-9]'
Это должно охватывать числа, выраженные как 12
, -1
, 0e + 12
], 01
, 0,0001
. Но не для 0xFF
или Inf
или NaN
, например, так что это все равно будет отличаться от более канонического:
POSIXLY_CORRECT=1 awk -v n=0 -F , '$2 != 0 {n++}; END{print n}'
Если ваш ввод содержит числа, выраженные в такой формат.
Для решения, содержащего только sed
, вы могли бы:
sed '/^[^,]*,[-+0-9]*[1-9]/!d' | sed -n '$='
Но для решения с одним вызовом sed
нам нужно было бы выполнять арифметические действия вручную.
sed -n '
1{x;s/$/0,:0123456789,0/;x;}
/^[^,]*,[-+0-9]*[1-9]/ {
x;:1
s/^,/1/;s/\(.\),\(.*:.*\1\(,*.\)\)/\3\2/;t1
s/:/,:/
x
}
${x;s/,.*//p;}'