我需要在 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 {} \;
但我不知道如何在一行上组合find
和打印输出。sed
有什么帮助吗?
提前致谢!
答案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 {} \;
还将处理空文件和带有空格的文件名。 MacOS 用户可能无法basename
使用。
答案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/\([^/]*/\)*||'