【问题标题】:Shell program code about: regexp and file handlingShell 程序代码:正则表达式和文件处理
【发布时间】:2011-10-10 03:43:38
【问题描述】:

我正在用 shell 编写这个小程序:

#!/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

我想打印 else 上的东西,因此,这是打印正确的消息。例如:如果“$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) 注意我的代码中的 ATTENTION 标签。我注意到有一些可能性,例如:在之前、之后或之前或之后有空格。我相信输入文件的一致性,但如果它们发生变化,它就会爆炸。在这种情况下我能做什么?有没有一种优雅的方式来管理它? (例外?)

非常感谢!

【问题讨论】:

  • 这是用sh写的有什么特别的原因吗?你会在 Perl 或 Python 中得到一个更简洁的程序。
  • @Rafe: 是的,我别无选择,必须用 shell 编写。
  • 顺便说一句——如果你准备了一个精简版的代码,你可能会受到更多的关注——刚好足以展示错误行为。我什至不会看这个,除非它让我非常沮丧。
  • @dmckee:对不起,如果代码看起来很长,但实际上不是,也许我过度记录了它。不过,我认为我在[I]、[II]和[III]中写了清晰简洁的问题。对于我的下一个问题,我将尝试更紧凑。谢谢。
  • Kani,你不应该在“问题”中有三个不同的问题,我试图回答你选择的标题中提到的问题。剩下的我就不看了。只需要花费更多的时间来弄清楚您的要求,而不是我愿意投资。我怀疑其他潜在的帮助者也在同一条船上。

标签: linux shell


【解决方案1】:

我之前被=~运营商咬过。

原则上我会告诉你引用这个论点(即... =~ "$NOM"),但是 starting with bash 3.2 there is a special behavior=~ ""。比较罗嗦的link()说:

o 现在将字符串参数引用到 [[ 命令的 =~ (regexp) 运算符 强制字符串匹配,与其他模式匹配运算符一样。

E14) 为什么在正则表达式匹配中引用模式参数 条件运算符 (=~) 导致正则表达式匹配停止工作?

在 bash-3.2 之前的 bash 版本中,引用正则的效果 未指定 [[ 命令的 =~ 运算符的表达式参数。 实际效果是双引号所需的模式参数 反斜杠引用特殊模式字符,这会干扰 反斜杠处理由双引号单词扩展执行,并且是 与 == shell 模式匹配运算符的处理方式不一致 引用的字符。

在 bash-3.2 中,shell 被更改为在单引号中内部引用字符 =~ 运算符的双引号字符串参数,它抑制 正则表达式处理特殊字符的特殊含义 (.',[', \',(', ),*', +',?', {',|', ^', and$') 和力 他们要从字面上匹配。这与 `==' 模式是一致的 匹配运算符处理其模式参数的引用部分。

由于引用字符串参数的处理方式发生了变化,出现了几个问题 出现了,其中最主要的是模式论证中的空白问题 以及 bash-3.1 和 bash-3.2 之间对引用字符串的不同处理。 这两个问题都可以通过使用 shell 变量来保存模式来解决。 由于在所有扩展shell变量时不进行分词 [[ 命令的操作数,这允许用户根据需要引用模式 分配变量时,然后将值扩展为单个字符串 可能包含空格。第一个问题可以通过使用反斜杠来解决 或任何其他引用机制来逃避模式中的空白。

您可能会考虑类似于NOM="[ ]NV" 的内容。 (请注意,我没有对此进行测试。)

【讨论】:

  • 感谢您的提示!等我能得到[I]、[II]和[III]的答案!!
【解决方案2】:

嗯,感谢帮助我的人。根据他们的建议,我将回答我自己的问题:

关于:

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++ 程序)或 shell 脚本(例如,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\>'

【讨论】:

    猜你喜欢
    • 2015-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-14
    • 2014-02-05
    相关资源
    最近更新 更多