다음 형식의 파일이 있습니다.
[#] 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 ']['
}
입력에서 관련 열을 잘라내고 문자열이 나타나는 행 번호를 검색한 다음 해당 행을 가져와 첫 번째 열의 숫자만 유지합니다.