파일 읽기 및 쓰기 : tee command


10

다음과 같은 명령이 잘 알려져 있습니다.

cat filename | some_sed_command >filename

명령 전에 실행되는 출력 리디렉션으로 파일 파일 이름을 지우면 파일 이름이 잘립니다.

다음과 같은 방법으로 문제를 해결할 수 있습니다.

cat file | some_sed_command | tee file >/dev/null

그러나 이것이 어떤 경우에도 작동하는지 확실하지 않습니다. 파일 (및 sed 명령의 결과)이 매우 큰 경우 어떻게됩니까? 운영 체제에서 아직 읽지 않은 일부 내용을 덮어 쓰지 않으려면 어떻게해야합니까? 나는 어떤 경우에도 작동 해야하는 스폰지 명령이 있음을 알 수 있습니다. 티보다 "더 안전"합니까?


주요 목표는 무엇입니까? (간단한 용어로)
Sergiy Kolodyazhnyy

@Serg는 단순히 일이 어떻게 작동하는지 이해합니다 ... kos의 답변은 문제를 명확하게합니다
VeryHardCoder

답변:


10

다음과 같은 방법으로 문제를 해결할 수 있습니다.

cat file | some_sed_command | tee file >/dev/null

없음 .

가능성 file은 줄어 들지만 잘리지 않는다는 보장 cat file | some_sed_command | tee file >/dev/null은 없습니다 file.

파이프의 명령은 왼쪽에서 오른쪽으로 처리되지 않으므로 예상되는 것과는 달리 어떤 명령이 먼저 처리되는지에 달려 있습니다 . 일뿐만 아니라 단지 무작위로 고른으로 생각하고 수 있도록 명령을 먼저 포착 될에 대한 보장은 없다 결코 쉘이 잘못된 하나를 따기 여부에 의존하지 않습니다.

위반 명령이 세 명령 사이에서 먼저 선택 될 가능성이 두 명령 사이에서 처음으로 선택 될 가능성보다 낮기 file때문에 잘릴 가능성은 적지 만 여전히 발생 합니다.

script.sh:

#!/bin/bash
for ((i=0; i<100; i++)); do
    cat >file <<-EOF
    foo
    bar
    EOF
    cat file |
        sed 's/bar/baz/' |
        tee file >/dev/null
    [ -s file ] &&
        echo 'Not truncated' ||
        echo 'Truncated'
done |
    sort |
    uniq -c
rm file
% bash script.sh
 93 Not truncated
  7 Truncated
% bash script.sh
 98 Not truncated
  2 Truncated
% bash script.sh
100 Not truncated

따라서 같은 것을 사용 하지 마십시오 cat file | some_sed_command | tee file >/dev/null. spongeOli가 제안한대로 사용하십시오 .

대안으로, 더 단단한 환경 및 / 또는 상대적으로 작은 파일의 경우 명령이 실행되기 전에 here 문자열과 명령 대체를 사용하여 파일을 읽을 수 있습니다.

$ cat file
foo
bar
$ for ((i=0; i<100; i++)); do <<<"$(<file)" sed 's/bar/baz/' >file; done
$ cat file
foo
baz

9

를 들어 sed구체적으로, 당신은 사용할 수 있습니다 -i현재 위치에서 인수를. 열린 파일에 다시 저장합니다. 예 :

sed -i 's/ /-/g' filename

당신은 당신보다 더 많은 일을하는지 가정, 뭔가 beefier에 작업을 수행하려면 sed, 그래, 당신이 가진 모든 것을 버퍼링 할 수 있습니다 sponge(로부터 moreutils파일을 밖으로 쓰기 전에 모든 표준 입력을 "흡수"할 패키지). 그것은처럼 tee미만 기능을. 그러나 기본 사용법의 경우 대체 대체품입니다.

cat file | some_sed_command | sponge file >/dev/null

더 안전합니까? 명확히. 어마 어마한 일을하고 있다면 (sed로 편집 할 수없는 경우), 두 번째 파일을 편집 한 다음 mv해당 파일을 원래 파일 이름으로 되돌릴 수 있습니다. 그것은 원자 적이어야합니다 (따라서 지속적인 액세스가 필요한 경우 이러한 파일에 따른 모든 것이 중단되지 않습니다).


0

Ex 모드에서 Vim을 사용할 수 있습니다 :

ex -sc '%!some_sed_command' -cx filename
  1. % 모든 줄을 선택하십시오

  2. ! 명령을 실행

  3. x 저장하고 종료


0

아, 그러나 sponge유일한 옵션은 아닙니다. moreutils이 작업을 제대로 수행하기 위해 얻을 필요는 없습니다 . 다음 두 가지 요구 사항을 충족하는 한 모든 메커니즘이 작동합니다.

  1. 출력 파일 이름을 매개 변수로 승인합니다.
  2. 모든 입력이 처리 된 후에 만 ​​출력 파일을 작성합니다.

OP가 언급하고있는 잘 알려진 문제는 셸이 파이프 라인에서 명령을 실행하기 전에 파이프가 작동하는 데 필요한 모든 파일을 생성한다는 것입니다. 그래서 실제로 잘리는 쉘입니다 명령이 실행되기 전에 출력 파일 (불행히도 입력 파일이기도 함).

tee명령은 작동하지 않습니다조차 만족하는 첫 번째 요구하지만, 그것은 두 번째 요구 사항을 만족하지 않기 때문에 : 그것은 바로 출력 파일에 파이프를 만들기로 나쁜 본질적 그래서 항상 시작, 즉시 출력 파일을 생성합니다. (실제로 사용하면 출력 파일이 잘 리기 전에 결정적이지 않은 임의 지연이 발생하므로 실제로는 그렇지 않지만 작동한다고 생각할 수 있습니다.)

따라서이 문제를 해결하기 위해 필요한 것은 출력을 생성하기 전에 모든 입력을 버퍼링하고 출력 파일 이름을 매개 변수로 허용 할 수있는 명령이므로 출력을 파이프에 연결할 필요가 없습니다. 출력 파일 그러한 명령 중 하나는 shuf입니다. 따라서 다음은 동일한 작업을 sponge수행합니다.

    shuf --output=file --random-source=/dev/zero 

--random-source=/dev/zero부분 shuf은 셔플 링을 전혀하지 않고 작업을 수행하므로 입력을 변경하지 않고 버퍼링합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.