Scripting 使用Awk或Cut打印列?

Scripting 使用Awk或Cut打印列?,scripting,awk,unix,Scripting,Awk,Unix,我正在编写一个脚本,该脚本将文件名作为参数,在每行的开头找到一个单词和一个特定的单词,在本例中是单词ATOM,并打印特定列中的值 $FILE=*.pdb * if test $# -lt 1 then echo "usage: $0 Enter a .PDB filename" exit fi if test -r $FILE then grep ^ATOM $FILE | awk '{ print $18 }' | awk '{ print NR $4, "\t" $38,}' els

我正在编写一个脚本,该脚本将文件名作为参数,在每行的开头找到一个单词和一个特定的单词,在本例中是单词ATOM,并打印特定列中的值

$FILE=*.pdb *

if test $# -lt 1
then
 echo "usage: $0 Enter a .PDB filename"
 exit
fi
if test -r $FILE
then
 grep ^ATOM $FILE | awk '{ print $18 }' | awk '{ print NR $4, "\t" $38,}'
else
 echo "usage: $FILE must be readable"
 exit
fi
我很难找出三个问题:

  • 如何使用awk仅打印包含ATOM作为第一个单词的行
  • 如何使用awk仅打印符合上述条件的行中的某些列,特别是列2-20和38-40
  • 我如何指示这必须是pdb文件?*。pdb*
  • 那就是

    awk '$1 == "ATOM"' $FILE
    
  • 使用
    cut
    可以更好地完成该任务:

    grep ^ATOM $FILE | cut -c 2-20,38-40
    
  • 如果要确保作为脚本的第一个参数传递的文件名以
    .pdb
    结尾:首先,请不要这样做(文件扩展名在UNIX中并不重要),其次,如果必须这样做,这里有一种方法:

    "${1%%.pdb}" == "$1" && echo "usage:..." && exit 1
    
    这将获取第一个命令行参数(
    $1
    ),去掉后缀
    .pdb
    (如果存在),然后将其与原始命令行参数进行比较。如果它们匹配,则它没有后缀,因此程序将打印一条使用消息并以状态代码1退出


  • 与答案相反,您的任务只需一个awk命令即可完成。不需要grep或cut或

    if [ $# -lt 1 ];then
     echo "usage: $0 Enter a .PDB filename"
     exit
    fi
    FILE="$1"
    case "$FILE" in
    *.pdb )
    
    if test -r $FILE
    then 
     # do for 2-20 assuming whites paces as column separators
     awk '$1=="ATOM" && NF>18 { 
       printf "%s ",$2
       for(i=3;i<=19;i++){
         printf "%s ",$i
       }
       printf "%s",$20   
     }' "$FILE"
    else
     echo "usage: $FILE must be readable"
     exit
    fi
    ;;
    *) exit;;
    esac
    
    if[$#-lt 1];然后
    echo“用法:$0输入.PDB文件名”
    出口
    fi
    FILE=“$1”
    中的大小写“$FILE”
    *.pdb)
    如果测试-r$文件
    然后
    #假设空格作为列分隔符,则执行2-20
    awk'$1==“原子”&&NF>18{
    printf“%s”,2美元
    
    对于(i=3;i您可以在本机
    bash
    中执行所有需要的操作,而无需生成任何子进程:

    #!/bin/bash
    
    declare    key="ATOM"
    declare    print_columns=( 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 38 39 40 )
    
    [ ! -f "${1}" ] && echo "File not found." && exit
    [ "${1%.pdb}" == "${1}" ] && echo "File is wrong type." && exit
    
    while read -a columns; do
      if [ ${columns[0]} == ${key} ]; then
        printf "%s " ${key}
        for print_column in ${print_columns[@]}; do
          printf "%s " ${columns[${print_column}]}
        fi
        printf "\n"
      fi
    done < ${1}
    
    !/bin/bash
    declare key=“ATOM”
    声明打印列=(2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 19 20 38 39 40)
    [!-f“${1}]”和&echo“未找到文件”。&&exit
    [“${1%.pdb}”==“${1}”]&&echo“文件类型错误。”&&exit
    当读a列时;做
    如果[${columns[0]}=${key}];则
    printf“%s”${key}
    对于${print_columns[@]};do中的print_列
    printf“%s”${columns[${print\u column}]}
    fi
    printf“\n”
    fi
    完成<${1}
    
    谢谢David!我能问你为什么说“请不要”,因为参数不能仅限于.pdb文件吗?如果我需要打印的列只能是在第18-30列中有条目的类型,我应该分别对每个列使用管道吗?grep^ATOM$1 | cut-f 18-30 | cut-f 2-20,38-40@Koala:关于文件名,如果你想使用你的程序怎么办在一个名称以
    .txt
    ?或
    .csv
    ?或
    .bak
    ?结尾的文件上,或者在一个名称完全没有扩展名的文件上?仅仅因为文件名不符合某些任意约定而使程序失败,这不是一种愚蠢的做法吗?当然,这是您的程序,因此,如果您使用ant,但如果我的经验可以作为指导的话,那么最终会有一天,您会想要取消该检查。其他UNIX实用程序(例如
    grep
    awk
    )不要检查文件名,这是有原因的。至于你问题的第二部分,关于列,我真的不明白你在问什么。问题第二部分的澄清:如果列18-30中有内容,那么输出将显示列2-20、38-40的内容。我如何过滤?管道还是if-THEN语句?N我不知道该如何设置。啊,那会更复杂。我想不出一个方法来使用
    cut
    ,但是你可能可以做一些类似
    awk'$1==“ATOM”&&substr($0,18,13)!~/[^[:space:]/| cut-c2-20,38-40'
    (或者您可以在
    awk
    中完成整个过程,但程序会稍微长一点)。当然,这取决于您对“内容”的定义(在本例中,我假设它表示任何非空白字符串)。