![파일 정보를 다른 파일로 이동](https://linux55.com/image/190213/%ED%8C%8C%EC%9D%BC%20%EC%A0%95%EB%B3%B4%EB%A5%BC%20%EB%8B%A4%EB%A5%B8%20%ED%8C%8C%EC%9D%BC%EB%A1%9C%20%EC%9D%B4%EB%8F%99.png)
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
그래서 Paul의 세부사항을 옮기고 싶습니다...
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
스크립트는 두 개의 파일을 백업 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
이제 현재 및 이전 직원 텍스트 파일을 확인하여 변경 사항을 확인하십시오.