programing

명령어로 파일을 사용하여 출력을 잘라내지 않고 같은 파일로 리다이렉트하려면 어떻게 해야 합니까?

javajsp 2023. 4. 19. 22:15

명령어로 파일을 사용하여 출력을 잘라내지 않고 같은 파일로 리다이렉트하려면 어떻게 해야 합니까?

기본적으로 파일에서 입력 텍스트로 가져와 해당 파일에서 행을 제거한 후 출력을 동일한 파일로 다시 보냅니다.더 명확해진다면 이 선들을 따라가는 뭔가가 있을 거야

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

그런데 이렇게 하면 빈 파일이 나와요.무슨 생각 있어?

이런 일에는 스펀지를 사용하세요.모레유틸리티의 일부입니다.

다음 명령을 사용해 보십시오.

 grep -v 'seg[0-9]\{1,\}\.[0-9]\{1\}' file_name | sponge 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}

해서 '아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 이런mktempTmp 파일을 작성하는데 POSIX가 아님을 주의해 주세요.

대신 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 editor(Vim의 일부).

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

여기서:

  • '+cmd'/-c - Ex/Vim 명령어 실행
  • g/pattern/d- global을 사용하여 패턴과 일치하는 선을 제거합니다.help :g)
  • -s 모드 「」)man ex)
  • -c wq - 행행:write ★★★★★★★★★★★★★★★★★」:quit, 명령어

하면 .sed(다른 답변에서 이미 나타난 바와 같이) 동일한 것을 달성한다. 단, (다른 답변에서 이미 나타난 바와 같이)-i)는 비표준 FreeB입니다.SD 확장자(Unix/Linux 간에 다르게 동작할 수 있음)는 기본적으로 파일 편집기가 아닌 스트림 편집기입니다.참조: Ex 모드는 실제로 사용됩니까?

이 질문이 검색 엔진에서 가장 중요한 결과이기 때문에, 여기 https://serverfault.com/a/547331을 기반으로 한 하위 셸 대신 하위 셸을 사용하는 원라이너가 있습니다.sponge OS 바닐라 설치의 (OS X는 바닐라 가 아닙니다).

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

일반적인 경우는 다음과 같습니다.

echo "$(cat file_name)" > file_name

편집. 위의 솔루션에는 몇 가지 경고가 있습니다.

  • printf '%s' <string>echo <string> 때문에, 「」를 포함한 -n★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
  • 명령어 치환에서는 줄바꿈이 삭제되므로(이것은 bash와 같은 셸의 버그/기능입니다), 다음과 같은 포스트픽스 문자를 추가해야 합니다.x다음과 같은 임시 변수의 매개 변수 확장을 통해 외부로 출력하고 제거합니다.${v%x}.
  • 변수 $v.$v표현식 전체를 괄호 안에 넣어 이전 값을 보존해야 합니다.
  • 또 다른 버그가 bash와 같이 인쇄할 수 없는 입니다.null출력에서 가져옵니다.는 이것을 했습니다.dd if=/dev/zero bs=1 count=1 >> file_name으로 보다cat file_name | xxd -pecho $(cat file_name) | xxd -p벗겨져 있습니다.따라서 이 답변은 Lynch가 지적한 바와 같이 바이너리 파일이나 인쇄 불가능한 문자를 사용하는 어떤 것에 사용해서는 안 됩니다.

일반적인 솔루션(약간 느리고 메모리 사용량이 많으며 인쇄 불가능한 문자를 제거하는 방법)은 다음과 같습니다.

(v=$(cat file_name; printf x); printf '%s' ${v%x} > file_name)

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

printf "hello\nworld\n" > file_uniquely_named.txt && for ((i=0; i<1000; i++)); do (v=$(cat file_uniquely_named.txt; printf x); printf '%s' ${v%x} > 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로부터 빌렸다.

One liner 대안 - 파일의 내용을 변수로 설정합니다.

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

이것은 매우 가능성이 있습니다.출력을 쓸 때까지 다른 파일에 쓸 필요가 있습니다.파일 기술자를 연 후 파일을 삭제하지만 쓰기 전에 이 작업을 수행할 수 있습니다.

exec 3<file ; rm file; COMMAND <&3 >file ;  exec 3>&-

또는 한 줄 한 줄 이해하기 위해 다음과 같이 하십시오.

exec 3<file       # open a file descriptor reading 'file'
rm file           # remove file (but fd3 will still point to the removed file)
COMMAND <&3 >file # run command, with the removed file as input
exec 3>&-         # close the file descriptor

COMMAND가 제대로 실행되지 않으면 파일 내용이 손실되기 때문에 여전히 위험한 작업입니다.이는 COMMAND가 0이 아닌 종료 코드를 반환하는 경우 파일을 복원함으로써 완화할 수 있습니다.

exec 3<file ; rm file; COMMAND <&3 >file || cat <&3 >file ; exec 3>&-

셸 함수를 정의하여 사용하기 쉽게 할 수도 있습니다.

# Usage: replace FILE COMMAND
replace() { exec 3<$1 ; rm $1; ${@:2} <&3 >$1 || cat <&3 >$1 ; exec 3>&- }

예:

$ echo aaa > test
$ replace test tr a b
$ cat test
bbb

또한 원본 파일의 전체 복사본이 유지됩니다(세 번째 파일 설명자가 닫힐 때까지).Linux 를 사용하고 있고 처리 중인 파일이 너무 커서 디스크에 두 번 들어갈 수 없는 경우 이 스크립트를 체크하면 이미 처리된 블록의 할당을 해제하면서 지정된 블록별로 파일을 파이핑할 수 있습니다.항상 그렇듯이 사용 페이지의 경고를 읽습니다.

이하와 같은 것을 실현합니다.sponge필요 없이 할 수 있습니다.moreutils:

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

--random-source=/dev/zero파트 트릭shuf조작을 전혀 하지 않고 조작할 수 있기 때문에, 조작을 변경하지 않고 입력을 버퍼링 할 수 있습니다.

그러나 성능상 임시 파일을 사용하는 것이 가장 좋습니다.일반적인 방법으로 이 기능을 수행할 수 있도록 제가 작성한 함수는 다음과 같습니다.

# 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

siphon()
{
    local tmp file rc=0
    [ "$#" -ge 2 ] || { echo "Usage: siphon filename [command...]" >&2; return 1; }
    file="$1"; shift
    tmp=$(mktemp -- "$file.XXXXXX") || return
    "$@" <"$file" >"$tmp" || rc=$?
    mv -- "$tmp" "$file" || rc=$(( rc | $? ))
    return "$rc"
}

이것은 내가 직면한 대부분의 경우에 꽤 효과가 있다.

cat <<< "$(do_stuff_with f)" > f

해 주세요.$(…) 바꿈, 줄 바꿈, 줄 바꿈, 줄 바꿈, 줄 바꿈,<<< 최종적인 새로운 라인이 보증되기 때문에 일반적으로 결과는 마법처럼 만족합니다.(여기 문자열 참조)man bash★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

완전한 예:

#! /usr/bin/env bash

get_new_content() {
    sed 's/Initial/Final/g' "${1:?}"
}

echo 'Initial content.' > f
cat f

cat <<< "$(get_new_content f)" > f

cat f

이렇게 해도 파일이 잘리지 않고 다음과 같은 결과를 얻을 수 있습니다.

Initial content.
Final content.

여기서 사용하는 기능은 명확성과 확장성을 위해 사용했지만, 필수는 아닙니다.

일반적인 사용 사례는 JSON 에디션입니다.

echo '{ "a": 12 }' > f
cat f
cat <<< "$(jq '.a = 24' f)" > f
cat f

그 결과:

{ "a": 12 }
{
  "a": 24
}

그리고 또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

POSIX Awk에서는 slurp를 사용할 수 있습니다.

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

이거 드셔보세요

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

cat testfile
AAA
BBB
CCC

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

저는 보통 티 프로그램을 사용합니다.

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

temp 파일을 스스로 작성 및 삭제합니다.

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