Bash:读入文件,编辑行,输出到新文件

Bash: Read in file, edit line, output to new file

我是 linux 的新手,也是脚本编写的新手。我在使用 bash 的 linux 环境中工作。我需要做以下事情: 1.逐行读取一个txt文件 2.删除第一行 3.去掉第一行之后的中间部分 4. 复制修改到一个新的txt文件

第一行之后的每一行都有三部分,第一部分始终以 .pdf 结尾,第三部分始终以 R0 开头,但中间部分不一致。

文件中 2 行的示例:

R01234567_High Transcript_01234567.pdf  High School Transcript  R01234567
R01891023_Application_01891023127.pdf   Application R01891023

这是我目前所拥有的。我只是在读取文件,将其打印到屏幕并将其复制到另一个文件。

#! /bin/bash
cd /usr/local/bin;
#echo "list of files:";
#ls;
for index in *.txt;
do echo "file: ${index}";
echo "reading..."
exec<${index}
value=0
while read line
do
   #value='expr ${value} +1';
   echo ${line};
done
echo "read done for ${index}";
cp ${index} /usr/local/bin/test2;
echo "file ${index} moved to test2"; 
done 

所以我的问题是,如何删除每一行的中间位,在 .pdf 之后但在 R0...之前?

假设标签删除的更新答案

既然有制表符分隔符,那么这对 awk 来说是小菜一碟。借用我最初删除的答案和@geek1011 删除的答案:

awk -F"\t" '{print , $NF}' infile.txt

此处 awk 按制表符拆分文件中的每条记录,然后打印第一个字段 </code> 和最后一个字段 <code>$NF 其中 NF 是内置的 awk记录字段数的变量;通过在前面加上一个美元符号,它表示“记录中最后一个字段的值”。


原始答案假设 space 定界符

留在这里以防有人像我最初假设的那样 space 分隔废话。

您可以使用 awk 而不是使用 bash 来通读文件:

awk 'NR>1{for(i=1; $i!~/pdf/; ++i) firstRec=firstRec" "$i} NR>1{print firstRec,$i,$NF}' yourfile.txt

awk 逐行读取文件并处理它遇到的每条记录。字段由白色 space 自动分隔。第一个字段是 </code>,第二个字段是 <code>,依此类推。 awk 已内置变量;这里我们使用NF,这是记录中包含的字段数,NR,这是当前正在处理的记录号。

此脚本执行以下操作:

  1. 如果记录号大于1(不是表头)则
  2. 循环遍历每个字段(此处以白色 space 分隔),直到找到包含“pdf”的字段 ($i!~/pdf/)。将我们在该字段之前找到的所有内容存储在名为 firstRec 的变量中,由 space (firstRec=firstRec" "$i).
  3. 分隔
  4. 打印出 firstRec,然后打印出我们停止迭代的任何字段(包含“pdf”的字段),即 $i,最后打印出记录中的最后一个字段, 即 $NF (print firstRec,$i,$NF)

您可以将其定向到另一个文件:

awk 'NR>1{for(i=1; $i!~/pdf/; ++i) firstRec=firstRec" "$i} NR>1{print firstRec,$i,$NF}' yourfile.txt > outfile.txt

sed 可能是一种更简洁的方式,因为如果您的 pdf 文件有多个 space 分隔字符,那么您将丢失多个 spaces.

使用sed:

sed 's/^\(.*\.pdf\).*\(R0.*\)$/ /g' file.txt 

这将删除 .pdfR0 之间的所有内容,并将其替换为单个 space。

您的示例的结果:

R01234567_High Transcript_01234567.pdf R01234567
R01891023_Application_01891023127.pdf R01891023

艰难、不可靠的方式

它有点冗长,比我们知道字段由制表符文字分隔时更有意义简洁和高效,但以下循环执行此处理在没有外部工具的纯原生 bash 中:

shopt -s extglob
while IFS= read -r line; do
  [[ $line = *".pdf"*R0* ]] || continue # ignore lines that don't fit our format

  filename=${line%%.pdf*}.pdf
  id=R0${line##*R0}
  printf '%s\t%s\n' "$filename" "$id"
done

${line%%.pdf*} returns 行中第一个 .pdf 之前的所有内容; ${line%%.pdf*}.pdf 然后将 .pdf 附加到该内容。

同样,${line##*R0} 扩展到最后一个 R0 之后的所有内容; R0${line##*R0} 因此扩展为以 R0 开头的最终字段(假设这是文件中该字符串的唯一实例)。


简单的方法(使用制表符分隔符)

如果 cat -t file(在 MacOS 上)或 cat -A file(在 Linux 上)在字段之间(但不在字段内)显示 ^I 序列,请使用以下命令相反:

while IFS=$'\t' read -r filename title id; do
  printf '%s\t%s\n' "$filename" "$id"
done

这会将三个制表符分隔的字段读入名为 filenametitleid 的变量,并发出 filenameid 字段。

您可以像这样在每个 line 上使用 sed

line="R01234567_High Transcript_01234567.pdf  High School Transcript  R01234567"
echo "$line" | sed 's/\.pdf.*R0/\.pdf R0/'
# output 
R01234567_High Transcript_01234567.pdf R01234567

这会将 .pdfR0 之间的任何内容替换为空格键。 它不处理一些边缘情况,但它简单明了