シェルスクリプトを使用してファイルの特定の部分を変更します。

シェルスクリプトを使用してファイルの特定の部分を変更します。

この形式を使用してコマンドラインで提供されたファイルから単語を検索する最も簡単な方法は何ですか?

./<file1> -f <file2> --edit <id> <column> <value>

<id>人を検索して与えられた単語を変えたいです<file2><column><value>

頑張りました

awk -F '|' -v ID="$4" -v Column="$5" \
           -v Value="$6" 'ID==$1 {$Column=Value ;}1' \
           OFS='|' $2>NewFile
mv NewFile $2 ;

しかし、一時ファイルなしでタスクを実行したいと思います。

たとえば、

1000|text1|text2|text3
1001|text4|text5|text6
1002|text7|text8|text9

私が処刑した後

./<file> -f file2 --edit 1001 2 Marios

次のように変更する必要があります。

1000|text1|text2|text3
1001|Marios|text5|text6
1002|text7|text8|text9

答え1

一時ファイルなしでテキストファイルを編集するのは悪い考えであり、通常Unixスクリプトでは実行されません。ファイル全体を再作成するか、少なくとも編集の影響を受けるサフィックス部分を再作成する必要があります。書き込みが中断されるとファイルが破損します。

もちろん、私たちは毎日テキストエディタを使ってこれを行います。ファイルをメモリに保存して保存すると、ディスクに上書きされます。違いは、すべてのまともなエディタが機能が明示的に無効になっていない限り、少なくともバックアップを維持し(追加ファイルであり、おそらくユーザーが許可できない)、エディタが対話型であることです。何らかの理由で保存が失敗した場合(ディスクが損傷していない場合、システムがクラッシュした場合、何でも)、ある人はそれを知っています。競合が発生しない場合、エディタは実行中であり、保存に失敗してもファイルはメモリに残ります。ユーザーはコマンドを実行してファイルを別の場所に保存したり、特定の状況を解決するためにプログラムの外部でいくつかの操作を実行した後に再保存を試みることができます。

TXRソリューション:インメモリコピーから上書き、バックアップ、または回復戦略なし:

#!/usr/local/bin/txr --lisp

(defvarl myname [*args-full* 2])

;; check for required arguments syntax
(unless (and (= (length *args*) 6)
             (equal [*args* 0] "-f")
             (equal [*args* 2] "--edit"))
  (put-line `usage: @myname -f <file> --edit <col1-key> <col-num> <replace>`)
  (exit 1))

;; do in-memory update and overwrite
(let ((file [*args* 1])
      (key [*args* 3])
      (col (pred (tointz [*args* 4]))) ;; pred, because [f #] is zero based
      (val [*args* 5])
      (ss (make-strlist-output-stream))) ;; in-memory string list stream

  ;; awk into memory
  (awk (:inputs file) ;; input from file
       (:output ss) ;; output stream is in-memory string list
       (:set fs "|") ;; field separator is pipe
       ((equal [f 0] key) (set [f col] val)) ;; do replacement
       (t)) ;; true condition with no action -> default print action

  ;; overwrite original file with string list
  (with-stream (out (open-file file "w"))
    (put-lines (get-list-from-stream ss) out)))

会議:

$ diff -u data.orig data
$ ./inplace 
usage: ./inplace -f <file> --edit <col1-key> <col-num> <replace>
$ ./inplace -f data --edit 1001 2
usage: ./inplace -f <file> --edit <col1-key> <col-num> <replace>
$ ./inplace -f data --edit 1001 2 Marios
$ diff -u data.orig data
--- data.orig   2016-10-16 08:05:03.233736781 -0700
+++ data    2016-10-16 08:15:57.412394022 -0700
@@ -1,3 +1,3 @@
 1000|text1|text2|text3
-1001|text4|text5|text6
+1001 Marios text5 text6
 1002|text7|text8|text9

答え2

あなたが探しているものの1つはコマンドライン解析です。case良い解析を行うために、POSIXシェルで使用できます。

Next AWKはこの変換を完全に実行できます。これを行うには、-iJohnが提案したようにGNU awk(with)を使用するか一時ファイルを使用する2つのオプションがあります。 POSIXではありませんが、mktemp使用法の例は次のとおりです。mktempほとんどすべての *nix システムに存在します。

#!/bin/sh

while test $# -gt 0
do
    case "$1" in
      -f)
      file="$2"
      shift
      shift
      ;;
      --edit)
      id="$2"
      column="$3"
      value="$4"
      shift
      shift
      shift
      shift
      ;;
      *)
      echo "Usage:"
      echo "  $0 -f <file> --edit <id> <column> <value>"
      exit
      ;;
  esac
done
# debug
echo "edit [$file] in [$id] change column [$column] to [$value]"

tmpf=`mktemp`
awk -v FS="|" -v OFS="|" "/^$id/ { \$$column = \"$value\" }1" "$file" > "$tmpf"
mv "$tmpf" "$file"

アイデアは、プログラムをawkに渡すときに正しい文字をエスケープすることです。上記のスクリプトが呼び出されると仮定すると、script.sh単に次のことができます。

./script.sh -f myfile --edit 1001 3 "It's a me Mario"

これにはまだいくつかの問題があります。これをクラスタ化しないように、以下で解決します。まず、引数の数が空であることも確認する必要があります。

if test $# -eq 0
then
    echo Usage
    exit
fi

第二に、平原を利用することはmv時々危険です。特に問題が発生し、スクリプトが出力を生成しない場合は、さらにそうです。mv入力を上書きするには、次のものを周囲に追加することをお勧めします。

if test -s "$tmpf"
then
    mv "$tmpf" "$file"
else
    echo Something went wrong
fi

答え3

次のファイルがあり、上記の出力を取得する必要があるとします。

入力ファイル:

1000|text1|text2|text3
1001|text4|text5|text6
1002|text7|text8|text9

出力は次のようになります。

1000|text1|text2|text3
1001|Marios|text5|text6
1002|text7|text8|text9

これを試してみてください:

grep -rn "1001" file1 | awk -F '|' '{export $2=<new value>;print $2}' \;
  1. デフォルトでは、grep -rn "1001" file1 次の行が提供されます。

    1001|text4|text5|text6

  2. 上記の出力を取得したら、次を使用して2番目の列( " "で区切られたフィールド)awkの値を変更します。|

現在、これを実装する環境はありませんが、このロジックがあなたが達成しようとする目標に役立つと確信しています。

結論:一時ファイル割り当てをより多く使用すると、サーバーでより多くのI / Oが発生し、結果としてパフォーマンスが低下し、サーバーが遅くなり、サーバーのパフォーマンスが低下するため、スクリプトで一時ファイルを使用しないことをお勧めします。

答え4

いくつかの簡単なコードのための1行のシェル関数ラッパーsed

# Usage: foo <file2> <id> <column> <value>
foo() { sed -i "/^$2|/s/[^|]*/$4/$3" "$1" ; }

例:

 foo file2 1001 2 Marios  ;  cat file2

出力:

1000|text1|text2|text3
1001|Marios|text5|text6
1002|text7|text8|text9

関連情報