我有一个文本文件,每一行包含一个文件名:
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
...
我应该如何更改我的脚本以获得所需的输出?
答案1
不要在 shell 中做这种事情!它比必要的复杂得多,容易出错,而且速度慢得多。有许多工具专为此类文本操作而设计。例如,在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 -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
答案2
除非您有特定需要为此使用 shell,特登的回答提供更好的替代方案。
由于您正在使用bash
(如脚本的 shebang 中所示),您可以使用该-n
选项来回显:
echo -n "${line} " >> output.txt
echo "$line" | cut -d'_' -f 1 >> output.txt
或者您可以使用 shell 功能来处理该行而不使用cut
:
echo "${line} ${line%%_*}" >> output.txt
(替换两条echo
线)。
或者,printf
也可以做到这一点,适用于任何POSIX外壳,并且通常更好(参见为什么 printf 比 echo 更好?详情):
printf "%s " "${line}" >> output.txt
echo "$line" | cut -d'_' -f 1 >> output.txt
或者
printf "%s %s\n" "${line}" "${line%%_*}" >> output.txt
(严格来说,简单来说/bin/sh
,echo -n
不便携。由于您明确使用,bash
因此这里可以。)
答案3
给你:
#!/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