この形式を使用してコマンドラインで提供されたファイルから単語を検索する最も簡単な方法は何ですか?
./<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はこの変換を完全に実行できます。これを行うには、-i
Johnが提案したように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}' \;
デフォルトでは、
grep -rn "1001" file1
次の行が提供されます。1001|text4|text5|text6
上記の出力を取得したら、次を使用して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