Подсчитать ненулевые числа для каждой строки второго столбца в текстовом файле

Прав доступа на выполнение достаточно, чтобы ядро ​​могло выполнить файл.

Если файл начинается с #! , тогда он увидит, что это скрипт, проанализирует эту строку, чтобы узнать путь интерпретатора и необязательный аргумент, а затем запустит этот интерпретатор с этим необязательным аргументом и путем к файлу в качестве аргумента.

Например, если файл начинается с:

#! /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не пытается открыть файл для чтения.

0
19.05.2016, 12:39
3 ответа

Вы можете использовать параметр -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 '$='
1
28.01.2020, 02:27

С grep :

grep -c '^[^,]*,[^0]' <file

Это работает, только если 2-й столбец сформирован как целое число, но не -0 , +0 . Для более общего случая см. @ Ответ Стефана Хазеласа .

1
28.01.2020, 02:27
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;}'
1
28.01.2020, 02:27

Теги

Похожие вопросы