Оболочка кода программы о: регулярное выражение и обработка файлов - PullRequest
0 голосов
/ 09 октября 2011

Я пишу эту маленькую программу в оболочке:

#!/bin/bash

#***************************************************************
# Synopsis:
# Read from an inputfile each line, which has the following format:
#
# llnnn nnnnnnnnnnnnllll STRING lnnnlll n nnnn nnnnnnnnn nnnnnnnnnnnnnnnnnnnn ll ll   
#
# where:
# n is a <positive int>
# l is a <char> (no special chars)
# the last set of ll ll  could be:
#   - NV 
#   - PV 
#
# Ex:
# AVO01  000060229651AVON FOOD OF ARKHAM C A  S060GER   0  1110  000000022  00031433680006534689  NV  PV
#
# The program should check, for each line of the file, the following:
# I) If the nnn of character llnnn (beggining the line) is numeric,
#    this is, <int>
# II) If the character ll ll is NV (just one set of ll) then
#    copy that line in an outputfile, and add one to a counter. 
# III) If the character ll ll is NP (just one set of ll) then
#     copy that line in an outputfile, and add one to a counter.
# 
# NOTICE: could be just one ll. Ex: [...] NV [...]
#                                   [...] PV [...] 
#         or both Ex: [...] NV PV [...] 
#
#
# Execution (after generating the executable):
# ./ inputfile outputfileNOM outputfilePGP
#***************************************************************


# Check the number of arguments that could be passed.
if [[ ${#@} != 3 ]]; then
        echo "Error...must be: myShellprogram <inputfile> <outputfileNOM> <outputfilePGP>\n"
    exit
fi  

#Inputfile: is in position 1 on the ARGS
inputfile=$1 
#OutputfileNOM: is in position 2 on the ARGS
outputfileNOM=$2
#OutputfilePGP: is in position 3 on the ARGS
outputfilePGP=$3

#Main variables. Change if needed. 
# Flags the could appear in the <inputfile>
#
# ATTENTION!!!: notice that there is a white space
# before the characters, this is important when using
# the regular expression in the conditional:
# if [[  $line =~ $NOM ]]; then [...] 
#
# If the white space is NOT there it would match things like:
# ABCNV ... which is wrong!!
NOM=" NV"
PGP=" PV"
#Counters of ocurrences
countNOM=0;
countPGP=0;


#Check if the files exists and have the write/read permissions
if [[ -r $inputfile && -w $outputfileNOM && -w $outputfilePGP ]]; then
    #Read all the lines of the file.
    while read -r line  
        do
            code=${line:3:2} #Store the code (the nnn) of the "llnnn" char set of the inputfile

            #Check if the code is numeric
            if [[ $code =~ ^[0-9]+$ ]] ; then

                #Check if the actual line has the NOM flag
                if [[  $line =~ $NOM ]]; then
                    echo "$line" >> "$outputfileNOM"
                    (( ++countNOM ))
                fi  

                #Check if the actual line has the PGP flag
                if [[  $line =~ $PGP ]]; then
                    echo "$line" >> "$outputfilePGP"
                    (( ++countPGP ))
                fi

            else
              echo "$code is not numeric"
              exit  

            fi      

        done < "$inputfile"

    echo "COUN NON $countNOM"       
    echo "COUN PGP $countPGP"
else
    echo "FILE: $inputfile does not exist or does not have read permissions"
    echo "FILE: $outputfileNOM does not exist or does not have write permissions"
    echo "FILE: $outputfilePGP does not exist or does not have write permissions"
fi  

У меня есть несколько вопросов:

I) Когда я делаю:

 if [[ -r $inputfile && -w $outputfileNOM && -w $outputfilePGP ]]; then
 [...]
 else
     echo "FILE: $inputfile does not exist or does not have read permissions"
     echo "FILE: $outputfileNOM does not exist or does not have write permissions"
     echo "FILE: $outputfilePGP does not exist or does not have write permissions"
 fi

Я бынравится печатать вещи на другом, соответственно, это печатать правильные сообщения.Пример: если у «$ outputfileNOM» не было разрешения на запись, просто распечатайте эту ошибку.НО, я не хочу ставить много if / else, например:

if [[ -r $inputfile ]]; then
[...]
if  [[-w $outputfileNOM ]] then 
[...]
else
  For the READ permission, and the other else for the WRITE

Есть ли способ сделать это, без с использованием подхода вложенности, и это поддерживаетудобочитаемость

II) О:

 if [[ -r $inputfile && -w $outputfileNOM && -w $outputfilePGP ]]

все в порядке, если я использую флаг "-x" вместо -r или -w.У меня нет четкого определения того, что означает:

-x FILE
          FILE exists and execute (or search) permission is granted

III) Обратите внимание на метку ВНИМАНИЕ в моем коде.Я заметил, что есть некоторые возможности, например: наличие пробелов до, после или до или после.Я верю в согласованность входных файлов, но если они изменятся, они взорвутся.Что я мог сделать в этом случае?Есть ли элегантный способ управлять этим?(исключения?)

Большое спасибо!

Ответы [ 2 ]

0 голосов
/ 09 октября 2011

Ну, спасибо людям, которые помогли мне. Со своими предложениями я отвечу на свои вопросы:

О

I) Хотя в этом решении используются условные выражения, он очень элегантен:

#File error string
estr='ERROR: %s files does no exist or does not have %s permissions.\n'  

#Check if the files exists and have the write/read permissions
[ -r $inputfile ] || { printf "$estr" "<$inputfile>" "read" && exit; }
[ -w $outputfileNOM ] || { printf "$estr" "<$outputfileNOM>" "write" && exit; }
[ -w $outputfilePGP ] || { printf "$estr" "<$outputfilePGP>" "write" && exit; }

Уведомление ; после выхода!

II) Из руководства chmod :

Буквы rwxXst выбирают биты режима файла для затронутых пользователей: чтение (r), запись (w), выполнение (или поиск каталогов) (x) ...

И из Википедия (Разрешения файловой системы):

Разрешение на чтение, которое дает возможность читать файл. Когда установлено для каталога, это разрешение предоставляет возможность читать имена файлов в каталоге (но не узнавать дополнительную информацию о них, такую ​​как содержимое, тип файла, размер, владение, разрешения и т. Д.)

Разрешение на запись, которое дает возможность изменять файл. Когда установлено для каталога, это разрешение дает возможность изменять записи в каталоге. Это включает в себя создание файлов, удаление файлов и переименование файлов.

Разрешение на выполнение, которое дает возможность выполнить файл. Это разрешение должно быть установлено для исполняемых двоичных файлов (например, скомпилированной программы C ++) или сценариев оболочки (например, программы Perl), чтобы позволить операционной системе их запускать. При установке для каталога это разрешение предоставляет возможность обходить его дерево для доступа к файлам или подкаталогам, но не для просмотра содержимого файлов в каталоге (если не установлено чтение).

III) Спасибо @dmckee за ссылку и черепахе .

# ATTENTION!!!: notice the \< and \> surrounding
# the characters, this is important when using
# the regular expression in the conditional:
# if [[  $line =~ $NOM ]]; then [...]
#
# If those characters are NOT there it would match things like:
# ABCNV ... which is wrong!!
# They (the \< and \>) indicate that the 'NV' can't be 
# contained in another word.
NOM='\<NV\>'
PGP='\<PV\>'
0 голосов
/ 09 октября 2011

Раньше меня укусил оператор =~.

В принципе, я бы сказал, чтобы вы указали аргумент (то есть ... =~ "$NOM"), , но начиная с bash 3.2, существует специальное поведение с =~ "".Ссылка (), которая довольно многословна, говорит:

o Заключение строкового аргумента в оператор [[command's = ~ (regexp) теперь вызывает сопоставление строк, как и в случае других операторов сопоставления с образцом.

и

E14) Почему цитирование аргумента шаблона условному оператору соответствия регулярному выражению (= ~) приводит к тому, что сопоставление регулярного выражения перестает работать?

В версиях bash до bash-3.2 эффект цитирования аргумента регулярного выражения для оператора [[command's = ~ не был указан.Практический эффект заключался в том, что двойные кавычки аргумента шаблона требовали обратной косой черты для кавычек специальных символов шаблона, что мешало обработке обратной косой черты, выполняемой раскрытием двойных кавычек, и несовместимо с тем, как оператор сопоставления с шаблоном оболочки == обрабатывал символы в кавычках.

В bash-3.2 оболочка была изменена на символы внутренних кавычек в строковых аргументах в одинарных и двойных кавычках для оператора = ~, который подавляет специальное значение символов, специфичное для обработки регулярных выражений (.', [', \', (', ),* ', +',?', {', | ', ^', and $') и вынуждает их сопоставлять буквально. Это согласуется с тем, как `== 'Оператор сопоставления с образцом обрабатывает заключенные в кавычки части своего аргумента шаблона.

С тех пор, как изменилась обработка строковых аргументов в кавычках, возникло несколько проблем, главная из которых - проблема пробелов в аргументах шаблона и различная обработка строк в кавычкахмежду Баш-3.1 и Баш-30,2.Обе проблемы могут быть решены с помощью переменной оболочки для хранения шаблона.Поскольку разделение слов не выполняется при развертывании переменных оболочки во всех операндах команды [[, это позволяет пользователям указывать шаблоны по своему усмотрению при назначении переменной, а затем расширять значения до одной строки, которая может содержать пробелы.Первая проблема может быть решена с помощью обратной косой черты или любого другого механизма цитирования, чтобы избежать пробелов в шаблонах.

Вы можете рассмотреть что-то вроде NOM="[ ]NV".(Обратите внимание, что я не проверял это.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...