development

명령에서 파일을 사용하고 출력을 자르지 않고 동일한 파일로 리디렉션하려면 어떻게해야합니까?

big-blog 2020. 9. 23. 07:53
반응형

명령에서 파일을 사용하고 출력을 자르지 않고 동일한 파일로 리디렉션하려면 어떻게해야합니까?


기본적으로 파일에서 입력 텍스트로 가져 와서 해당 파일에서 한 줄을 제거하고 출력을 동일한 파일로 다시 보내고 싶습니다. 이 선을 따라 가면 더 명확 해집니다.

grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name > file_name

그러나 이렇게하면 빈 파일이 생깁니다. 이견있는 사람?


bash가 먼저 리디렉션을 처리 한 다음 명령을 실행하기 때문에 그렇게 할 수 없습니다. 따라서 grep이 file_name을 볼 때 이미 비어 있습니다. 그래도 임시 파일을 사용할 수 있습니다.

#!/bin/sh
tmpfile=$(mktemp)
grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name > ${tmpfile}
cat ${tmpfile} > file_name
rm -f ${tmpfile}

이와 같이 tmpfilemktemp 을 만드는 데 사용 하는 것을 고려 하지만 POSIX가 아니라는 점에 유의하십시오.


이런 종류의 작업 에는 스폰지사용하십시오 . moreutils의 일부입니다.

다음 명령을 시도하십시오.

 grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name | sponge file_name

대신 sed를 사용하십시오.

sed -i '/seg[0-9]\{1,\}\.[0-9]\{1\}/d' file_name

이 간단한 것을 시도하십시오

grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name | tee file_name

이번에는 파일이 비어 있지 않으며 출력도 터미널에 인쇄됩니다.


동일한 파일에 리디렉션 연산자 ( >또는 >>)를 사용할 수 없습니다. 우선 순위가 더 높고 명령이 호출되기 전에 파일을 생성 / 자르기 때문입니다. 그것을 방지하기 위해 다음과 같은 적절한 도구를 사용해야합니다 tee, sponge, sed -i또는 파일 (예에 대한 결과를 쓸 수있는 다른 도구 sort file -o file).

기본적으로 입력을 동일한 원본 파일로 리디렉션하는 것은 의미가 없으며이를 위해 적절한 내부 편집기 (예 : Ex 편집기 (Vim의 일부))를 사용해야합니다.

ex '+g/seg[0-9]\{1,\}\.[0-9]\{1\}/d' -scwq file_name

어디:

  • '+cmd'/ -c-Ex / Vim 명령 실행
  • g/pattern/d- 전역 ( help :g)을 사용하여 패턴과 일치하는 줄 제거
  • -s-무음 모드 ( man ex)
  • -c wq-실행 :write:quit명령

당신은 사용할 수 sed있지만, (이미 다른 답변에서와 같이) 동일을 달성하기 위해 자리에서 ( -i(유닉스 / 리눅스 사이에 다르게 작동 할 수 있습니다) 표준이 아닌 FreeBSD의 확장은) 기본적으로 그것은이다 tream 에드 당사 홈페이지가 아닌 파일 편집기 . 참조 : Ex 모드는 실용적인 용도가 있습니까?


하나의 라이너 대안-파일의 내용을 변수로 설정 :

VAR=`cat file_name`; echo "$VAR"|grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' > file_name

이 질문이 검색 엔진의 최상위 결과이므로 다음은 대신 하위 셸을 사용하는 https://serverfault.com/a/547331의 한 줄입니다 sponge(종종 OS X와 ​​같은 바닐라 설치의 일부가 아님).

echo "$(grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name)" > file_name

또는 일반적인 경우 :

echo "$(cat file_name)" > file_name

https://askubuntu.com/a/752451 에서 테스트 :

printf "hello\nworld\n" > file_uniquely_named.txt && for ((i=0; i<1000; i++)); do echo "$(cat file_uniquely_named.txt)" > file_uniquely_named.txt; done; cat file_uniquely_named.txt; rm file_uniquely_named.txt

다음을 인쇄해야합니다.

hello
world

cat file_uniquely_named.txt > file_uniquely_named.txt현재 쉘에서 호출하는 반면 :

printf "hello\nworld\n" > file_uniquely_named.txt && for ((i=0; i<1000; i++)); do cat file_uniquely_named.txt > file_uniquely_named.txt; done; cat file_uniquely_named.txt; rm file_uniquely_named.txt

빈 문자열을 인쇄합니다.

대용량 파일 (아마 2GB 또는 4GB 이상)에서는 테스트하지 않았습니다.

나는 Hart Simhakos 에게서이 대답을 빌렸다 .


도 있습니다 ed(대안으로 sed -i) :

# cf. http://wiki.bash-hackers.org/howto/edit-ed
printf '%s\n' H 'g/seg[0-9]\{1,\}\.[0-9]\{1\}/d' wq |  ed -s file_name

process-substitution 을 사용하여이를 수행 할 수 있습니다 .

bash가 모든 파이프를 비동기 적으로 열어서 sleepYMMV 를 사용하여 이를 해결해야하기 때문에 약간의 해킹 입니다.

귀하의 예에서 :

grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name > >(sleep 1 && cat > file_name)
  • >(sleep 1 && cat > file_name) grep에서 출력을받는 임시 파일을 만듭니다.
  • sleep 1 입력 파일을 구문 분석하는 grep 시간을 제공하기 위해 1 초 동안 지연
  • 마지막으로 cat > file_name출력을 씁니다.

POSIX Awk와 함께 slurp를 사용할 수 있습니다.

!/seg[0-9]\{1,\}\.[0-9]\{1\}/ {
  q = q ? q RS $0 : $0
}
END {
  print q > ARGV[1]
}


I usually use the tee program to do this:

grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name | tee file_name

It creates and removes a tempfile by itself.


Try this

echo -e "AAA\nBBB\nCCC" > testfile

cat testfile
AAA
BBB
CCC

echo "$(grep -v 'AAA' testfile)" > testfile
cat testfile
BBB
CCC

The following will accomplish the same thing that sponge does, without requiring moreutils:

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

The --random-source=/dev/zero part tricks shuf into doing its thing without doing any shuffling at all, so it will buffer your input without altering it.

However, it is true that using a temporary file is best, for performance reasons. So, here is a function that I have written that will do that for you in a generalized way:

# Pipes a file into a command, and pipes the output of that command
# back into the same file, ensuring that the file is not truncated.
# Parameters:
#    $1: the file.
#    $2: the command. (With $3... being its arguments.)
# See https://stackoverflow.com/a/55655338/773113

function siphon
{
    local tmp=$(mktemp)
    local file="$1"
    shift
    $* < "$file" > "$tmp"
    mv "$tmp" "$file"
}

참고URL : https://stackoverflow.com/questions/6696842/how-can-i-use-a-file-in-a-command-and-redirect-output-to-the-same-file-without-t

반응형