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

时间:2016-07-25 19:18:30

标签: linux bash shell rhel

我是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之前删除每一行的中间位??

4 个答案:

答案 0 :(得分:2)

使用sed

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

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

您的示例的结果:

R01234567_High Transcript_01234567.pdf R01234567
R01891023_Application_01891023127.pdf R01891023

答案 1 :(得分:1)

更新了答案,假设tab delim

由于有一个制表符分隔符,所以这对于awk来说很简单。借用我最初删除的答案和@ geek1011删除答案:

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

此处awk按标签拆分文件中的每条记录,然后打印第一个字段$1和最后一个字段$NF NF内置{{1} }}变量用于记录的字段数;通过预先加上一个美元符号,它会显示“记录中最后一个字段的值”。


假设空格分隔符的原始答案

留下这个,以防有人像我原先假设的那样有空格分隔。

您可以使用awk代替使用bash来阅读文件:

awk

awk 'NR>1{for(i=1; $i!~/pdf/; ++i) firstRec=firstRec" "$i} NR>1{print firstRec,$i,$NF}' yourfile.txt 逐行读取文件并处理它遇到的每条记录。字段由空格自动分隔。第一个字段是awk,第二个字段是$1,依此类推。 $2内置了变量;这里我们使用awk这是记录中包含的字段数,NF是当前正在处理的记录号。

此脚本执行以下操作:

  1. 如果记录号大于1(不是标题),则
  2. 遍历每个字段(此处用空格分隔),直到找到其中包含“pdf”的字段(NR)。将我们找到的所有内容存储到名为$i!~/pdf/的变量中的该字段,并以空格(firstRec)分隔。
  3. 打印出firstRec=firstRec" "$i,然后打印出我们停止迭代的任何字段(包含“pdf”的字段)firstRec,最后打印出记录中的最后一个字段,是$i$NF
  4. 您可以将此指向另一个文件:

    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文件有多个空格分隔字符,那么您将丢失多个空格。

答案 2 :(得分:1)

艰难,不可靠的方式

它有点冗长,并且很多比我们知道字段被制表符文字分隔的意义更简洁和有效,但是以下循环在纯本机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*}返回行中第一个.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字段。

答案 3 :(得分:0)

您可以在每个sed上使用line,如下所示:

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之间的任何内容。 它没有处理一些边缘情况,但它简单明了