我有两个文件,current_employee.txt
并且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 但它将所有员工详细信息移至 previous_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
用更新的记录替换当前员工的旧记录。
将上述稍微笨拙的命令包装在 shell 脚本中,并给它更多的空气:
#!/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
和两个文件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
现在检查现任和前任员工文本文件以查看更改。