열별 텍스트 파일 조회

열별 텍스트 파일 조회

다음 형식의 파일이 있습니다.

[#]   OWNER_NAME     NAME                       SIZE
[6]   Robottinosino  Software                   200
[42]  Robottinosino  Ideas worth zero           188
[12]  Robottinosino  Ideas worth zero or more   111
[13]  I am Batman    Hardware                   180
[25]  Robottinosino  Profile Pictures           170

명령줄 도구를 사용하여 다음을 수행하고 싶습니다.

my_command "Ideas worth zero"

다음 결과를 얻습니다.

42

다음 결과를 얻을 위험은 없습니다.

12

grep을 사용하여 첫 번째 필드를 가져오는 awk라는 줄을 식별하려고 생각했지만 텍스트 'OWNER_NAME' 및 ​​'SIZE'가 어느 열에 있는지 계산하는 것 외에 전체 'NAME' 필드를 안정적이고 효율적으로 일치시키는 방법을 잘 모르겠습니다. 헤더에 나타나고 약간의 공백을 제거하여 그 사이의 모든 것을 가져옵니다.

'OWNER_NAME'은 두 단어 이상일 수 있습니다. 예: 'OWNER_NAME' = "I am Batman".

구현과 관련된 아이디어가 있습니까?

여기서 알아야 할 것은 cat, head, tail, awk, sed, grep, cut 등의 오래된 계열입니다.

답변1

좋아요, 열의 길이를 알 수 없다면 bash보다 더 강력한 언어로 전환하겠습니다.

#!/usr/bin/perl
use warnings;
use strict;

my $string = shift;
open my $FH, '<', '1.txt' or die $!;
my $first_line = <$FH>;
my ($before, $name) = $first_line =~ /(.* )(NAME *)/;
my $column = length $before;
$string .= ' ' x (length($name) - length $string);     # adjust the length of $string
while (<$FH>) {
    if ($column == index $_, $string, $column) {
        /^\[([0-9]+)\]/ and print "$1\n";
    }
}

답변2

필드 너비가 일정한 경우(예: 필드 너비로 표시된 파일 형식이 최대값인 경우) GNU awk( gawk(1))를 사용하고 FIELDWIDTHS고정 너비 구문 분석을 사용하도록 변수를 설정할 수 있습니다.

gawk -v searchstr="Ideas worth zero" -- '
    BEGIN { FIELDWIDTHS="6 15 27 5" }  # assuming the final field width is 5
    # Pre-process data
    {
        gsub(/[^[:digit:]]/, "", $1)  # strip out non-numbers
        for (i = 2; i <= NF; i++)
            gsub(/[[:space:]]*$/, "", $i)  # strip trailing whitespace
    }
    # match here
    $3 == searchstr { print $1 }
' file.txt

이를 쉘 스크립트나 함수로 래핑하고 매개변수화할 수 있습니다 searchstr( -v searchstr="$1").

그러나 필드가 가변 너비인 경우(즉, 데이터가 변경되면 필드 너비가 변경될 수 있음) 첫 번째 줄을 검사하여 필드 너비를 좀 더 영리하고 동적으로 결정해야 합니다. 하나의 필드가 밑줄을 사용하여 호출되는 경우 OWNER_NAME필드 이름에 공백이 없다고 가정하므로 공백이 필드 이름을 구분한다고 가정할 수 있습니다.

이를 정의하면 해당 BEGIN...줄을 다음 코드로 바꿀 수 있습니다.

NR == 1 {
    for (i = 2; i <= NF; i++)
        FIELDWIDTHS=FIELDWIDTHS index($0" ", " "$i" ")-index($0" ", " "$(i-1)" ") " "
    FIELDWIDTHS=FIELDWIDTHS "5"  # assuming 5 is the width of the last field
    next
}

그러면 첫 번째 줄의 필드를 보고 두 번째 필드와 마지막 필드의 후속 필드 위치 간의 차이를 계산하여 필드 너비를 계산합니다. 나는 마지막 필드의 너비가 5라고 가정했지만 거기에 큰 숫자를 입력하면 남은 내용에도 작동할 것이라고 생각합니다.

NAME내부에서 찾을 수 없도록 OWNER_NAME(또는 이라는 필드가 있는 경우 ) 이름 앞뒤에 공백을 찾아야 하며 , 대신 전체 필드와 일치해야 합니다(또한 일치할 수 있도록 OWNER공백을 추가해야 합니다). $0거기에 아무것도 없더라도 끝에 공간이 있습니다).

에서만 일치하는 대신 필드 이름으로 쿼리할 수 있도록 더 멋지게 만들 수 있지만 $3그건 여러분에게 맡기겠습니다.

답변3

아마도 '0의 가치가 있는 아이디어'로 먼저 행을 필터링한 다음 '... 또는 그 이상' 행을 던지는 것이 가장 간단할 것입니다.

grep 'Ideas worth zero' | grep -v 'Ideas worth zero or more'

그리고 해당 파이프에서 숫자를 얻으려면 입력을 다음과 같이 하십시오.

cut -d' ' -f1 | tr -d ']['

공백으로 구분된 첫 번째 필드를 잘라내고 대괄호를 제거합니다.

적절한 필드 구분 기호가 제공되는 방식으로 파일 형식을 약간 변경할 수 있다면 가장 좋습니다.

답변4

이는 다음과 같은 도움이 될 수 있습니다.

function my_command () {
    sed -n $(cut -b22-48 1.txt |
        grep -n "$1"' *$' |
        cut -f1 -d: )p 1.txt \
            | cut -d' ' -f1 | tr -d ']['
}

입력에서 관련 열만 잘라내고 문자열이 나타나는 줄 번호를 검색한 다음 이 줄을 가져와서 첫 번째 열의 번호만 유지합니다.

관련 정보