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
サブディレクトリの1つにありますinput.txt
。この場所のサブディレクトリの1つ(1レベル)内のinput.txtにFILENAMEを持つファイルは1つしかありません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で一度に1行ずつ読み、アンダースコアに基づいて行を3つの部分に分割します。ファイル名を印刷してsedコマンドをトリガーし(デフォルトでは何も印刷しない)、指定された行番号に行を印刷してsedへの呼び出しを終了します。ファイル名の場所は、現在のディレクトリのすぐ下のディレクトリの1つになければなりません。
これにより、すべての出力が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
したがって、上記のスキームを使用すると、ファイルの2行目にFILE2.DAT_20180123_5
なりFILE2 b
、ファイルの7行目は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