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(不是表头)则
- 循环遍历每个字段(此处以白色 space 分隔),直到找到包含“pdf”的字段 (
$i!~/pdf/
)。将我们在该字段之前找到的所有内容存储在名为 firstRec
的变量中,由 space (firstRec=firstRec" "$i
). 分隔
- 打印出
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
这将删除 .pdf
和 R0
之间的所有内容,并将其替换为单个 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
这会将三个制表符分隔的字段读入名为 filename
、title
和 id
的变量,并发出 filename
和 id
字段。
您可以像这样在每个 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
这会将 .pdf
和 R0
之间的任何内容替换为空格键。
它不处理一些边缘情况,但它简单明了
我是 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(不是表头)则
- 循环遍历每个字段(此处以白色 space 分隔),直到找到包含“pdf”的字段 (
$i!~/pdf/
)。将我们在该字段之前找到的所有内容存储在名为firstRec
的变量中,由 space (firstRec=firstRec" "$i
). 分隔
- 打印出
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
这将删除 .pdf
和 R0
之间的所有内容,并将其替换为单个 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
这会将三个制表符分隔的字段读入名为 filename
、title
和 id
的变量,并发出 filename
和 id
字段。
您可以像这样在每个 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
这会将 .pdf
和 R0
之间的任何内容替换为空格键。
它不处理一些边缘情况,但它简单明了