我的文件夹中有许多“.txt”文件。
对于每个 .txt 文件,我需要获取文件名中的前 5 个字符,并将它们添加到文件中每行的开头。我还需要在新文件中每行的开头添加一个“*”符号。
我尝试使用以下命令,但它在文件中每行超过一个空格的文件中给出了错误的输出。
awk 'FNR == 1 {chr =substr(FILENAME, 0,5); name = FILENAME ".new" }{ printf("%s %s\n", "*"chr$1, $2) >name}' *.txt
有人可以修改代码或建议更简单的方法来执行此操作。
答案1
我将使用 shell 循环来迭代文件(这里假设 shell 支持${param:offset:length}
ksh93 中的运算符):
for f in *.txt
do
sed -i -- "s/^/*${f:0:5} /" "$f"
done
(假设文件名不包含反斜杠、换行符或&
字符)。
我的偏好是将数据写入一个新文件,当它们全部完成后,然后替换它们全体。这将允许处理中断的进程。但这不是我在这里所做的。
答案2
输出数据时没有理由只处理每行的前两个字段;只需打印$0
(整个原始行)即可:
awk '
FNR == 1 { close(name); chr = substr(FILENAME, 3, 5); name = FILENAME ".new" }
{ printf "*%s %s\n", chr, $0 >name }' ./*.txt
如果您愿意,可以使用print "*" chr, $0 >name
它来代替该语句。printf
或者,使用 shell 循环:
for name in *.txt; do
PREFIX=${name:0:5} awk '{ printf "*%s %s\n", ENVIRON["PREFIX"], $0 }' <"$name" >"$name.new"
done
在这里,我假设您使用的 shell 支持ksh93
's${param:offset:length}
运算符,例如 , ksh93
, bash
, zsh
, mksh
, busybox sh 。与 一起yash
使用,${name[1,5]}
代替${name:0:5}
(也适用于zsh
),或 POSIXly:${name%"${name#?????}"}
。
答案3
使用乐(以前称为 Perl_6)
~$ raku -e 'for @*ARGS { \
my $str = .substr(0..4); \
my @body = .IO.lines.map({ "*" ~ $str ~ $_ }); \
spurt($_ ~ "_new", @body.join("\n") ~ "\n" ); \
};' *.txt
或者:
~$ raku -e 'for @*ARGS -> $filename { \
my $str = $filename.substr(0..4); \
my @body = $filename.IO.lines.map({ "*" ~ $str ~ $_ }); \
spurt($filename ~ "_new", @body.join("\n") ~ "\n" ) \
};' *.txt
Raku 是 Perl 家族的一种编程语言。在 Raku 中,@*ARGS
是保存 shell 命令行上的参数的数组。简要地:
- 使用
for
数组@*ARGS
进行迭代, - 使用
substr
每个参数的前 5 个字符(例如文件名,此处为$_
或$filename
)被提取到$str
, - 每个参数(例如文件名)都被转换为一个
IO
对象并全部lines
被读取。行被修改,以便在每行的开头添加 和 ,并且这些修改的行被保存*
到,$str
@body
- 输出是通过该
spurt()
方法创建的,该方法采用文件路径(即新创建的文件的名称),后跟要写入的修改文本(@body
),并添加合适的换行符。
示例输入(示例文件名为fileA
):
>TCONS_00000867
>TCONS_00001442
>TCONS_00001447
>TCONS_00001528
>TCONS_00001529
>TCONS_00001668
>TCONS_00001921
>TCONS_00001922
示例输出(fileA_new
,根据需要修改文本):
*fileA>TCONS_00000867
*fileA>TCONS_00001442
*fileA>TCONS_00001447
*fileA>TCONS_00001528
*fileA>TCONS_00001529
*fileA>TCONS_00001668
*fileA>TCONS_00001921
*fileA>TCONS_00001922
https://course.raku.org/essentials/positionals/args-array/
https://docs.raku.org/language/variables#@*ARGS
https://docs.raku.org/type/independent-routines#sub_spurt
https://raku.org
答案4
在每行前面添加"*<first-5-bytes> "
:
perl -pi -e '$_ = "*" . substr($ARGV, 0, 5) . " $_"' -- *.txt
要在前面添加前 5 个字符而不是字节,它们本身根据区域设置的字符编码从文件名的字节中解码:
perl -MEncode::Locale -MEncode -pi -e '
$_ = "*".
encode(locale => substr(decode(locale_fs => $ARGV), 0, 5)).
" $_"' -- *.txt
或者避免对每一行执行“decode+substr+encode”操作:
perl -MEncode::Locale -MEncode -pi -e '
$prefix = "*".
encode(locale => substr(decode(locale_fs => $ARGV), 0, 5)).
" $_" if $. == 1;
$_ = $prefix . $_;
close ARGV if eof' -- *.txt
áéíóú123.txt
例如,对于在 UTF-8 语言环境中调用的文件会产生影响。
即使在一些存在这种区别的非 POSIX 系统中,使用locale_fs
而不是也可以使其工作。locale