ファイルに行がない場合は、どのようにファイルに複数の行を追加できますか?

ファイルに行がない場合は、どのようにファイルに複数の行を追加できますか?

ファイルに行がない場合は、どのようにファイルに複数の行を追加できますか?

たとえば、複数のグローバルエイリアスを追加するには、/etc/bash.bashrc次のようにします。ここのドキュメント:

cat <<-"BASHRC" >> /etc/bash.bashrc
    alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
    alias brc="nano /etc/bash.bashrc"
BASHRC

このタスクには、行がすでに存在するかどうかを確認する方法は含まれておらず、誤ってこの文書を再実行すると重複と競合が発生する可能性があるという批判を受けました。

答え1

ファイルの行newdataをに追加する簡単なシェルスクリプトですdatafilenewdataこの文書を変更するのは簡単です。これはgrep、すべての(新しい)入力ラインが必要なため、実際には非常に効率的ではありません。

target=datafile
while IFS= read -r line ; do
    if ! grep -Fqxe "$line" "$target" ; then
        printf "%s\n" "$line" >> "$target"
    fi
done < newdata 

各行に対してこれを使用して、固定文字列の一致(正規表現なし)、完全な行の一致、および一致する行の出力を抑制するためにターゲットgrepファイルにすでに存在することを確認します。一致する行がない場合は偽のエラーコードが返されるので、否定的な結果が真の場合はターゲットファイルに追加してください。-F-x-qgrep


では、より効率的に任意の行を配列のキーとして処理できる必要がありますawkawk

$ awk 'FNR == NR { lines[$0] = 1; next } ! ($0 in lines) {print}' datafile newdata 

最初の部分は、FNR == NR { lines[$0] = 1; next }最初の入力ファイルのすべての行を(関連付け)配列のキーとしてロードしますlines。 2番目の部分は! ($0 in lines) {print}次の入力ラインで動作し、そのラインが配列にない場合は「新しい」ラインを印刷します。

生成された出力には新しい行のみが含まれるため、元のファイルに追加する必要があります。例sponge:

$ awk 'FNR == NR { lines[$0] = 1; next } ! ($0 in lines) {print}' datafile newdata | sponge -a datafile

または、awk次の行を最後の行に追加することもできます。これを行うには、ファイル名を次のように渡しますawk

$ target=datafile 
$ awk -vtarget="$target" 'FNR == NR { lines[$0] = 1; next } 
                        ! ($0 in lines) {print >> target}' "$target" newdata

here-docを使用するには、リダイレクトの設定に加えて、awk(stdin)を明示的なソースファイルとして追加する必要があります。-awk ... "$target" - <<EOF

答え2

この解決策はあなたの考えとは少し異なるかもしれませんが、エイリアスが実際に定義されていることを確認し、そうでない場合はbashrcに追加するだけです。比較的最新バージョンのBashを使用すると仮定すると...

# instead of 'alias x=y' form put them in an associative array
declare -A aliases
aliases['a']='apple'
aliases['ba']='banana'

for key in "${!aliases[@]}"; do
    if ! alias "$key" > /dev/null 2>&1; then
        printf "alias %s='%s'\n" "$key" "${aliases[$key]}" >> /etc/bash.bashrc
    fi
done

unset aliases key

. ./scriptname通常のスクリプトとして実行するのではなくインポートします。

メモ:候補エイリアスがたくさんあり、それを連想配列形式に手動で変換することが慎重な場合は、次のようにファイルをvim編集してこのコマンドを実行できます:%s/\valias *([^=]+)\=['"]?([^'"]+)['"]?$/aliases['\1']='\2'/

または候補エイリアス(他は除く)をファイル(たとえば/tmp/aliases.txt)に入れ、aliases[..]='..'スクリプトの行を次に置き換えます。

while IFS= read -r a; do 
    eval "$a"; 
done < <(sed -E "s/alias  *([^=]+)=['\"]?([^'\"]+)['\"]?$/aliases['\1']='\2'/" /tmp/aliases.txt)

もちろん、AAを使用することに加えて他の方法もありますが、清潔で使いやすいです。今AAを使いたいです。 :)

答え3

正確なマッチングのための一般的なソリューション(パフォーマンスに最適化されていません)このファイルには確認inputする行が含まれています。

awk 'FNR==NR { lines[NR]=$0; next; };
    { for(i=1;i<=length(lines);i++) if ($0==lines[i]) matches[i]=1; print; };
    END { for(i=1;i<=length(lines);i++)
        if (matches[i]==0) print lines[i]; }' input file

テスト:

:> cat input
alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
alias brc="nano /etc/bash.bashrc"

:> cat file
a
b
c
alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
d

コマンドの出力は次のとおりですawk

a
b
c
alias rss="/etc/init.d/php*-fpm restart && systemctl restart nginx.service"
d
alias brc="nano /etc/bash.bashrc"

答え4

ええと。これはどうですか...

追加するエイリアスをファイルに入れます。新しい。それから...

cp bashrc bashrc.tmp && comm -23 <(sort -u new) <(sort -u bashrc.tmp) >> bashrc && rm -f bashrc.tmp

新しいエイリアスに対してこれを行い、bashrcコンテンツ(追加時に競合状態を避けるために一時ファイルに入れる)bashrc)そして実行してくださいcommcommソートされたファイルを1行ずつ比較し、一意で一般的な行を表示します。列 2 と 3( -23) は表示されないため、結果には対応する一意の行のみが表示されます。新しい私たちはそれらを次に追加しますbashrc。それはすべてです。

(これは、より多くの「1つのライナー」の探求に焦点を当てた他の答えとはまったく異なるアプローチです。)

関連情報