如何删除两个回显命令的输出之间的\ n?


13

我有一个文本文件,每行包含一个文件名:

111_c4l5r120.png
123_c4l4r60.png
135_c4l4r180.png
147_c4l3r60.png
15_c4l1r120.png
...

我想将其转换为以下形状:

111_c4l5r120.png 111
123_c4l4r60.png 123
135_c4l4r180.png 135
147_c4l3r60.png 147
15_c4l1r120.png 15
...

使用此代码:

#!/bin/bash
while IFS='' read -r line || [[  -n "$line"  ]]; do
   echo "$line" >> output.txt   
   echo "$line" | cut -d'_' -f 1 >> output.txt
done < "$1"

但是,结果是:

111_c4l5r120.png 
111
123_c4l4r60.png 
123
135_c4l4r180.png 
135
147_c4l3r60.png 
147
15_c4l1r120.png 
15
...

我应该如何更改脚本以获取期望输出?


Google找到了更好的结果,例如this
Thomas Dickey

Answers:


17

除非您特别需要为此使用shell,否则terdon的答案将提供更好的选择。

由于您正在使用bash(如脚本的shebang中所示),因此可以使用该-n选项进行回显:

echo -n "${line} " >> output.txt
echo "$line" | cut -d'_' -f 1 >> output.txt

或者,您可以使用外壳功能来处理行,而无需使用cut

echo "${line} ${line%%_*}" >> output.txt

(替换两echo行)。

另外,printf该技巧也可以在任何POSIX shell中工作,并且通常更好(有关详细信息,请参见为什么printf比echo好?):

printf "%s " "${line}" >> output.txt
echo "$line" | cut -d'_' -f 1 >> output.txt

要么

printf "%s %s\n" "${line}" "${line%%_*}" >> output.txt

(严格地说,在平原/bin/shecho -n是不可移植的。既然你明确地使用bash它的确定在这里。)


评论不作进一步讨论;此对话已转移至聊天
terdon

23

不要在外壳中做这种事情!它比必要的要复杂得多,容易出错,而且运行的速度远远不及预期。有许多用于此类文本操作的工具。例如,在sed(此处假设最新的GNU或BSD实现-E):

$ sed -E 's/([^_]*).*/& \1/' file
111_c4l5r120.png 111
123_c4l4r60.png 123
135_c4l4r180.png 135
147_c4l3r60.png 147
15_c4l1r120.png 15

或者,对于任何sed

$ sed 's/\([^_]*\).*/& \1/' file
111_c4l5r120.png 111
123_c4l4r60.png 123
135_c4l4r180.png 135
147_c4l3r60.png 147
15_c4l1r120.png 15

Perl:

$ perl -pe 's/(.+?)_.*/$& $1/' file
111_c4l5r120.png 111
123_c4l4r60.png 123
135_c4l4r180.png 135
147_c4l3r60.png 147
15_c4l1r120.png 15

awk:

$ awk -F_ '{print $0,$1}' file
111_c4l5r120.png 111
123_c4l4r60.png 123
135_c4l4r180.png 135
147_c4l3r60.png 147
15_c4l1r120.png 15

1
但是,外部实用程序并没有更好。
EKons,2016年

6
@ΈρικΚωνσταντόπουλος是的。实际上,速度要快几个数量级。外壳在这种事情上不是很好。毕竟,shell的主要工作是启动外部实用程序。将OP的方法所花费的时间与此处的任何解决方案所花费的时间进行比较。Shell循环非常非常慢。如果您需要更令人信服的内容,请阅读此内容
terdon

就便携性而言,不。在速度方面,是的。另外,@StéphaneChazelas是您的别名吗?
EKons,2016年

4
@):不,他刚写了2个与两个评论主题相关的好答案。至于可移植性,除了perl方法的(次要)例外(仅适用于约90%的* nix机器),所有这三种解决方案都是可移植的,并且与外壳无关。或者,好的,您可以随时将其加入sed其中以sed 's/\([^_]*\).*/& \1/' file实现额外的可移植性。关键是,您可以依靠awksed在那里拥有比您可以依靠的其他任何东西更多的东西。
terdon

2

这个给你:

#!/bin/bash

while IFS='' read -r line || [[  -n "$line"  ]]; do
   echo "$line" `echo "$line" | cut -d'_' -f 1` >> output.txt
#   echo "$line" | cut -d'_' -f 1 >> output.txt
done < "$1"

输出:

$ rm -rf output.txt
$ ./test.sh 1.1; cat output.txt
111_c4l5r120.png 111
123_c4l4r60.png 123
135_c4l4r180.png 135
147_c4l3r60.png 147
15_c4l1r120.png 15
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.