파일 이름 및 줄 번호 목록에서 특정 줄을 찾아 인쇄합니다.

파일 이름 및 줄 번호 목록에서 특정 줄을 찾아 인쇄합니다.

input.txt다음 형식의 여러 파일 이름이 포함된 파일이 있습니다 . FILENAME_DATE_LINENUMBER, input.txt그러한 파일 이름이 많이 포함되어 있습니다. 파일 이름 자체에는 정확히 5개의 밑줄이 있습니다..

FILE_NAME_1.DAT_20180123_4
FILE_NAME_2.DAT_20180123_5
FILE_NAME_3.DAT_20180123_6
FILE_NAME_4.DAT_20180123_7

모든 파일은 로 시작합니다 . 구문 분석 하고 각 파일 이름을 반복하고 FILENAME 및 지정된 줄 번호( FILENAME )를 인쇄하고 input.txt싶습니다.input.txtoutput.txt

나는 sed 또는 awk를 사용할 것이며 다음 명령이 작업을 수행할 것이라는 것을 알고 있습니다.

awk 'FNR==LINENUMBER {print FILENAME, $0}' *.txt >output.txt

하지만 어떻게 파일을 반복 input.txt하고 FILENAME을 찾고 FILENAME에서 LINENUMBER를 추출하여output.txt

지정된 FILENAME은 input.txt하위 디렉터리 중 하나에 있을 수 있습니다 input.txt. 이 위치의 하위 디렉터리 중 하나(한 수준) 내 input.txt에 FILENAME이 있는 파일은 하나만 있을 수 있습니다 input.txt.

DIR
├── input.txt
│   ├── DIR1
│   │   ├── FILE_NAME_1.DAT
│   ├── DIR2
│   │   ├── FILE_NAME_2.DAT
│   ├── DIR3
│   │   ├── FILE_NAME_3.DAT

다음 output.txt과 같이 인쇄되어야 합니다.

FILENAME
LINE( Extracted from FILENAME present in input.txt )

답변1

#!/bin/bash                                                                                   

do_one() {
    # two args: $1=filename_no_dir $2=line_number                                             
    # Find the single filename                                                                
    eval file=*"/$1"
    echo $1
    # $. == line number                                                                       
    perl -ne 'chomp; $.=='"$2"' and print "LINE($_)\n"' $file
}
export -f do_one

# Generate som test data                                                                      
parallel 'mkdir DIR{}; seq 100 110 >DIR{}/FILE_NAME_{}.DAT' ::: {1..4}

# Test input.txt                                                                              
cat <<EOF |                                                                                   
FILE_NAME_1.DAT_20180123_4                                                                    
FILE_NAME_2.DAT_20180123_5                                                                    
FILE_NAME_3.DAT_20180123_6                                                                    
FILE_NAME_4.DAT_20180123_7                                                                    
EOF                                                                                           
  # Remove _YYYYMMDD.* to get filename, and .*_ to get line number                            
  parallel do_one '{= s/_201\d\d\d\d\d.*// =}' '{= s/.*_// =}'

산출:

FILE_NAME_1.DAT
LINE(103)
FILE_NAME_2.DAT
LINE(104)
FILE_NAME_3.DAT
LINE(105)
FILE_NAME_4.DAT
LINE(106)

답변2

:> awk -F_ '{ print $1; print $3; }' inputfile
FILE1.DAT
4
FILE2.DAT
5
FILE3.DAT
6
FILE4.DAT
7

답변3

내가 올바르게 이해했다면

while IFS=_ read -r filename unuseddate linenum
do
  printf "%s\n" "$filename"
  sed -n "${linenum}{p;q}" */"$filename"
done < input.txt > output.txt

input.txt에서 한 번에 한 줄씩 읽고 밑줄을 기준으로 줄을 세 부분으로 나눕니다. 파일 이름을 인쇄한 다음 sed 명령을 트리거하고(기본적으로 아무것도 인쇄하지 않음) 지정된 줄 번호에 줄을 인쇄하고 sed에 대한 호출을 종료합니다. 파일 이름의 위치는 현재 디렉터리의 바로 하위 디렉터리 중 하나에 있어야 합니다.

그러면 모든 출력이 output.txt로 리디렉션됩니다.

답변4

GNU의 복잡한 솔루션parallel+find+awk:

각 입력 파일의 내용이 다음과 유사하다고 가정합니다.

cat DIR1/FILE1.DAT_20180123_4
FILE1 a 
FILE1 b 
FILE1 c 
FILE1 d 
FILE1 e 
FILE1 f 
FILE1 g

따라서 위 구성표를 사용하면 파일의 두 번째 줄이 FILE2.DAT_20180123_5되고 FILE2 b파일의 일곱 번째 줄은 FILE4.DAT_20180123_7- 가 됩니다 FILE4 g. input.txt파일이 질문과 동일하다고 가정합니다 .

일하다:

find . -type f -regextype posix-egrep -regex ".*/($(paste -s -d'|' input.txt))" \
| parallel -j0 "awk -v n="{=s/.*_//=}" -v fn="{/}" \
               'NR==n{ print fn,\$0; exit }' {}" > output.txt

최종 output.txt콘텐츠:

$ cat output.txt 
FILE4.DAT_20180123_7 FILE4 g
FILE3.DAT_20180123_6 FILE3 f 
FILE1.DAT_20180123_4 FILE1 d 
FILE2.DAT_20180123_5 FILE2 e

관련 정보