我有一個文字文件,每一行包含一個文件名:
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