2つのエコーコマンドの出力間の\ nを削除する方法は?


13

各行に1つのファイル名を含むテキストファイルがあります。

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
...

スクリプトを変更して、desireを出力させるにはどうすればよいですか?


Googleは、これなどのより良い結果を見つけます。
トーマスディッキー

回答:


17

このためにシェルを使用する特別な必要がない限り、terdonの答えはより良い代替手段を提供します。

あなたが使っているので、bash(スクリプトのシェバングに示されているように)、あなたは使用することができ-n、エコーのオプションを:

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

または、シェル機能を使用して、次を使用せずに行を処理できます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。)


コメントは詳細なディスカッション用ではありません。この会話はチャットに移動さました
テルドン

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

6
@ΈρικΚωνσταντόπουλοςはい。実際には数桁高速です。シェルはこの種のことにはあまり向いていません。結局のところ、シェルの主な仕事は外部ユーティリティを起動することです。OPのアプローチにかかった時間と、ここにあるいずれかのソリューションにかかった時間を比較してください。シェルループは非常に低速です。さらに説得力が必要な場合は、こちらをお読みください。
テルドン

移植性の面では、いや。速度の面では、はい。また、@StéphaneChazelasは別名ですか?
-EKons

4
@ΈρικΚωνσταντόπουλοςΘα 'θελα:)いいえ、彼はたまたま2つのコメントスレッドに関連する2つの素晴らしい回答を書いただけです。移植性については、* nixマシンの約90%のようなものでのみ動作するperlアプローチの(マイナーな)例外を除き、3つのソリューションはすべて移植可能で、シェルに依存しません。または、OK、いつでも追加の移植性sedを実現できますsed 's/\([^_]*\).*/& \1/' file。ポイントは、あなたが数えることができる、であるawksedより多くのあなたが他のほとんど何を数えることができるよりも、そこにいます。
テルドン

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.