current_employee.txt
2つのファイルがあり、従業員が辞職した場合は、その情報をからにformer_employee.txt
移動する必要があります。退社される方の情報を移動したい点ご了承ください。current_employee.txt
former_employee.txt
current_employee.txt
ように
name:john
surname:James
salary:3000
department:finance
name:Paul
surname:Perez
salary:5000
department:inventory
name:Abel
surname:Wood
salary:4000
department:inventory
だからポールの詳細を移動したいのですが…
cat current_employee.txt>former_employee.txtを試しましたが、すべての従業員の詳細が前の_employee.txtに移動されました。すべての調査をしましたが、何ができるか理解できません。
答え1
awk -v name=Paul '
BEGIN { RS=""; FS=":"; ORS="\n\n"; name = tolower(name) }
tolower($2) == name { print; next }
{ print >(FILENAME ".new") }' current_employee.txt >>former_employee.txt
これはコマンドライン(ここPaul
)に名前を付けていくつかのことを行います。入力ファイルを間に空行があるレコードセットとして扱いますcurrent_employee.txt
(そうしますRS=""
)。これらのレコードはそれぞれに基づいてフィールドに分割されているため:
(name
行が常に最初であると仮定)、$1
常にラベルでname
従業員$2
の名前です。
次に、出力レコード区切り文字を二重改行に設定して、コードによって出力される各レコードの最後に常に空行があることを確認します。また、クエリ文字列の大文字と小文字が正確であると完全に信頼できない場合(john
たとえば、すでにすべて小文字)、クエリ名は小文字で表示されます。
入力ファイルから読み取られた現在のレコードの小文字の名前が小文字のクエリ文字列と同じ場合、レコード全体が出力され、プログラムは入力の次の行にジャンプを使用しますnext
。
現在のレコードの名前が私たちが探している名前ではない場合、そのレコードも出力されますが、入力ファイルと同じファイル名を持つファイルとして出力されます.new
。
コードの出力はawk
次のとおりです。追加>>
ファイルとしてformer_employee.txt
。
つまり、実行すると次のような結果が出ます。
$ ls
current_employee.txt
$ cat current_employee.txt
name:john
surname:James
salary:3000
department:finance
name:Paul
surname:Perez
salary:5000
department:inventory
name:Abel
surname:Wood
salary:4000
department:inventory
$ awk -v name=Paul '
BEGIN { RS=""; FS=":"; ORS="\n\n"; name = tolower(name) }
tolower($2) == name { print; next }
{ print >(FILENAME ".new") }' current_employee.txt >>former_employee.txt
$ ls
current_employee.txt current_employee.txt.new former_employee.txt
$ cat former_employee.txt
name:Paul
surname:Perez
salary:5000
department:inventory
$ cat current_employee.txt.new
name:john
surname:James
salary:3000
department:finance
name:Abel
surname:Wood
salary:4000
department:inventory
その後利用できます
mv current_employee.txt.new current_employee.txt
現在の従業員の以前の履歴を更新された履歴に置き換えます。
上記の少し不器用なコマンドをシェルスクリプトでラップして、より活気に満ちてください。
#!/bin/sh
for file in current_employee.txt former_employee.txt
do
if [ -f "$file" ] && cp "$file" "$file-orig"; then
printf 'Backed up %s as %s-orig\n' "$file" "$file"
fi
done
awk -v name="$1" '
BEGIN {
RS = ""
FS = ":"
ORS = "\n\n"
name = tolower(name)
}
tolower($2) == name { print; next }
{ print >(FILENAME ".new") }' current_employee.txt >>former_employee.txt &&
mv current_employee.txt.new current_employee.txt
current_employee.txt
スクリプトは 2 つのファイルをバックアップformer_employee.txt
し、スクリプトの最初の引数として指定された名前に基づいて更新します。
通常、このスクリプトを使用します。
$ ./script Paul
答え2
GNU awk ユーティリティ v4.1.0 以降と inplace オプションを使用して、ファイルをその場で編集します。
# set input n output filenames
if=current_employee.txt
of=former_employee.txt
gawk -F: -i inplace -v n="John" '
/^name:/&&tolower($2)==tolower(n),!NF{
print >> OUT;next
}1
' OUT="$of" "$if"
GNU行エディタを使用して編集します。
### set input n output filenames
if=current_employee.txt
of=former_employee.txt
### user defined function to make changes
fx() {
## unpack arguments
n=$1
## escape any regex chars in name
for e in \\ \[ ^ \$ . \* /;do
n=${n//"$e"/\\"$e"}
done
## make name case insensitive
set -- {a..z}
for UC in {A..Z}; do
lc=$1; shift
n=${n//[$lc$UC]/"[$lc$UC]"}
done
## define the block which contains the name e.g., john
block="?^name:${n}\$?;/^\$/"
## invoke ed editor to make changes
ed -s "$if" <<eof
# add a dummy line to eof
a
.
# append block to former employee file
${block}W $of
# delete block from current employee file
${block}d
# take away the dummy line added
\$d
# save n quit from the current employee file
wq
eof
}
## and now invoke fx to make the changes in files
fx 'john'
### end
次に、現在および以前の従業員のテキストファイルを確認して変更を確認します。