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.txt
output.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