이 형식을 사용하여 명령줄에 제공된 파일에서 단어를 검색하는 가장 쉬운 방법은 무엇입니까?
./<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
당신이 찾고 있는 것 중 하나는 명령줄 구문 분석입니다. case
좋은 구문 분석을 수행하기 위해 POSIX 쉘에서 사용할 수 있습니다.
Next AWK는 이 변환을 완벽하게 수행할 수 있습니다. 이를 수행하려면 -i
John이 제안한 대로 GNU awk(with)를 사용하거나 임시 파일을 사용하는 두 가지 옵션이 있습니다. 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
위의 출력을 얻은 후에는 다음을 사용하여 두 번째 열( " "로 구분된 필드)
awk
의 값을 변경합니다.|
현재는 이를 구현할 환경이 없지만 이 논리가 귀하가 달성하려는 목표에 도움이 될 것이라고 확신합니다.
결론: 임시 파일 할당을 더 많이 사용하면 서버에서 더 많은 I/O가 발생하여 결과적으로 성능이 저하되고 서버가 느려지므로 서버 성능이 저하되므로 스크립트에서 임시 파일을 사용하지 않는 것이 좋습니다.
답변4
몇 가지 간단한 코드를 위한 한 줄짜리 셸 함수 래퍼 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