#!/bin/bash
FILES=/tmp/files.txt
FIELDNAME=/tmp/fieldname.txt
num=$(wc -l < $FIELDNAME)
#to read fieldname.txt content
FILE1=$1
cat $FILE1 > FILE2
value=$(<FILE2)
#to create empty lines
yes '' | sed $num\q >> $FILES
#to add fieldname content into files.txt
I=0
for fieldname in $value
do
echo "Line number $((I++)) --> $fieldname"
sed -i -e "i\input $fieldname " $FILES
sed -i -e 's/^/ /' $FILES
#to remove empty lines
sed -i '/^[[:space:]]*$/d' $FILES
done
sed -i '/^[[:space:]]*$/d' $FILES
私のスクリプト名はscript.shで、これがスクリプトを呼び出す方法です。
./script.sh fieldname.txt
予想される結果は次のとおりです。
input abc
input def
input ghi
しかし、私が得た出力はソートされておらず、次のように3行以上です。
input ghi
input def
input ghi
input abc
input ghi
input def
input ghi
input abc
input ghi
input def
input ghi
input abc
答え1
仕組みを誤解しているようですsed
。ファイルから sed コマンドを実行すると、ファイル全体が読み取られ、編集ルールが適用されます。すべて行(規則に適用場所を制限する「アドレス」行がない場合)したがって、あなたの例では、3つの空行のみを持つファイルで始まり、そのファイルを実行すると、sed -i -e "i\input $fieldname "
「enter abc」などのファイルの前に行が追加されます。これらの3行はそれぞれ。したがって、次のファイルがあります。
input abc
input abc
input abc
(安全ではありませんが、最後に空白があります。)彼らは、あなたが実行するとsed -i -e 's/^/ /'
前に4つのスペースを追加します。すべて行(空行を含む):
input abc
input abc
input abc
その後、実行するとsed -i '/^[[:space:]]*$/d'
実際に期待どおりに実行されます。空白のみの行を削除し、次のままにします。
input abc
input abc
input abc
その後、ループの次の反復でrunを実行すると、sed -i -e "i\input def "
既存の各行の前に新しい行が再配置されます。
input def
input abc
input def
input abc
input def
input abc
次に、sed -i -e 's/^/ /'
各行にもう4つのスペースを追加します(すでにスペースがある行を含む)。
input def
input abc
input def
input abc
input def
input abc
...など。これはあなたがしたいことをするわけではありません。別の言葉。
あなたがやろうとしていることを私が理解しているなら、sed
それは実際に仕事に適したツールではありません。既存のファイルを編集しようとするのではなく、新しいファイルを作成して1行ずつ追加したいようです。次のように簡単にこれを行うことができます。
: >"$FILES" # This empties the file (in case there's something there from last run)
I=0
for fieldname in $value
do
echo "Line number $((I++)) --> $fieldname"
echo " input $fieldname" >>"$FILES" # Append a line to the end of the file
done
「行番号...」エントリを印刷する必要がない場合、またはstdoutの代わりにstderrに送信できる場合(実際のエラーでなくても通常ステータス情報を送信する必要がある場所)、次のことができます。はるかに簡単です。
I=0
for fieldname in $value
do
echo "Line number $((I++)) --> $fieldname" >&2 # The >&2 redirects to standard error
echo " input $fieldname"
done >"$FILES" # Just send *all* standard output from the loop into the file
どちらの場合も、ファイルnum
の出力やプリロードは不要です。yes
ここには一見悪い慣行がたくさんあります。まず、変数参照は"$FILES"
上記の例のようにほぼ常に二重引用符で囲む必要があります。これにより、誤って複数の「単語」に分割されたり、ファイル名のワイルドカードに拡張されたりするのを防ぎます。私はお勧めしますshellcheck.netこのような一般的な間違いを指摘してください。
$value
()を使用してこれを実行しなかったことに注意してください。for fieldname in $value
この場合、変数の値を単語に分割するためにシェルに依存するためです...これは特に安全ではありません。本当に繰り返したいですか?性格入力ファイルにあるか、ループが必要です。ワイヤー代わりに?行が必要な場合は、そのfor ... in
構成を使用せずにread
ループを使用してください。
I=0
while read fieldname
do
echo "Line number $((I++)) --> $fieldname" >&2
echo " input $fieldname"
done <"$FILE1" >"$FILES" # Read input from $FILE1, write output to $FILES
バラよりBashFAQ#001:「ファイル(データストリーム、変数)を1行ずつ(および/またはフィールドごとに)どのように読みますか?」より多くの情報を知りたいです。
@Kusalanandaが(現在削除された)コメントで指摘したように、これを1行ずつ実行し、「行番号...」出力がまったく必要ない場合、シェルsed
ループでは使用できません。自分自身を取得し、sed
入力ファイルをスキャンしてinput
各行に「」を追加します。
sed 's/^/ input /' "$FILE1" >"$FILES"
とにかく、現在$ FILE1を文字通り「FILE2」というファイルにコピーし、それをvalue
変数という名前で読み込んでいます。これらのいずれも、元のファイルから直接読み取る必要はありません。
また、注:すべて大文字名の代わりに小文字または大文字と小文字の混合変数名を使用してください。シェルやその他のツールに特別な意味を持つ大文字の名前がたくさんあり、そのうちの1つを誤って使用すると奇妙なことが発生する可能性があります。