サブフォルダを含むフォルダ内のすべてのtxtファイルの最初の行を読み取り、ファイル名と最初の行を別のファイルに印刷します。

サブフォルダを含むフォルダ内のすべてのtxtファイルの最初の行を読み取り、ファイル名と最初の行を別のファイルに印刷します。

Ubuntuシステムから約20,000個のtxtファイルを読み取り、次のように各ファイルの最初の行を新しいtxtファイルに挿入する必要があります。

Filename1.txt | FirstLineoftheFilename1.txt
Filename2.txt | FirstLineoftheFilename2.txt
Filename3.txt | FirstLineoftheFilename3.txt

sedコマンドを試しましたが、最初の行を印刷できます。

次のfindコマンドは正しいファイルを識別します。

find /db/users/logs/ -name '*.txt' -exec sed -n '1p' {} \; -exec basename {} \;

しかし、出力を1行にまとめて印刷する方法がわかりませんfindsed

助けが必要ですか?

よろしくお願いします!

答え1

GNUを使用できますawk

LC_ALL=C find /db/users/logs/ -name '*.txt' -type f -exec gawk '{
  f = FILENAME; sub(".*/", "", f)
  print f" | "$0; nextfile}' {} +

またはperl:

LC_ALL=C find . -type f -name '*.txt' -exec perl -lne '
  print $ARGV =~ s:.*/::r . " | $_"; close ARGV' {} +

またはシェル:

LC_ALL=C find /db/users/logs/ -type f -name '*.txt' -exec sh -c '
  for file do
    <"$file" IFS= read -r line || [ -n "$line" ] &&
      printf "%s\n"  "${file##*/} | $line"
  done' sh {} +

sh(この方法は、最初の行にNUL文字が含まれている場合、ほとんどの実装では正しく機能しません。テキスト文書)。

答え2

別のバリエーションがあります:

$ find /db/users/logs/ -type f -name "*.txt" -exec \
  sh -c 'printf "%s | %s\n" "$(basename $1)" "$(head -1 $1)"' shellproc {} \;

空のファイルとスペースを含むファイル名も処理されます。basenameMacOSユーザーは使用できない可能性があります。

答え3

方法-a)

find /db/users/logs -type f -name '*.txt' \
    ! -empty -printf '%f | ' \
    -exec head -n 1 \{\} \;

find方法ii)PerlモジュールFile::Findを使用してコマンドの機能をカプセル化します。

perl -MFile::Find -e '
  find( sub { my $fh;
     -f && ! -z && /\.txt$/ and 
     open($fh, "<", $_) and 
     print("$_ | " . <$fh>) },
   shift )
' /db/users/logs

基本名の必要性を指摘してくれたStephaneに感謝します。ファイル名に改行文字がない場合でもこれを行うことができ、パイプの代わりにコロンを区切り文字として使用できます。

$ find /db/users/logs/  \
    -type f -name '*.txt' \
    -exec grep -Hm1 "^" {} + |
  sed 's|^/db/users/logs/\([^/]*/\)*||' 

関連情報