파일에서 여러 특수 문자를 어떻게 제거합니까?

파일에서 여러 특수 문자를 어떻게 제거합니까?

아래 스크립트는 현재 ^M 문자( Ctrl+V+M)를 제거합니다. 내용이 좀 긴 것 같지만 ^I와 앞으로 볼 수 있는 다른 문자도 추가해야 합니다.

^I( )를 추가하는 더 쉬운 방법이 있나요 Ctrl+V+I? 이것은 제가 약 6개월 전 2일간의 쉘 프로그래밍 수업에 참석한 후 직접 작성한 첫 번째 스크립트입니다. 필요한 것보다 더 길게 만든 것인지 확실하지 않으므로 일반적인 팁도 알려주시면 감사하겠습니다.

#!/bin/bash  

    echo "$# item(s) to review."
    question='Do you want to remove the ^M characters?'

    for file
    do
            if grep "^M" "$file" >> /dev/null 2> /dev/null
            then
                    echo "$file contains special characters"
                    echo $question
                    read answer
                            if    [[ "$answer" == [yY] ]]
                            then
                                    cat "$file" | sed "s/^M//" > "$file.safe"
                                    echo "Special characters have been removed and $file.safe has been created."
                            elif  [[ "$answer" == [yY][eE][sSaA]* ]]
                            then
                                    cat "$file" | sed "s/^M//" > "$file.safe"
                                    echo "Special characters have been removed and $file.safe has been created."
                            else
                                    echo "Special characters have NOT been removed."
                            fi
            elif [[ -d $file ]]
            then
                    echo "$file is a directory"
            else
                    echo "No special characters in $file"
            fi
    done

답변1

이것은 확실히 필요한 것보다 훨씬 더 깁니다. 당신에게 필요한 것은tr공익사업, 스크립트에 인수로 전달되는 파일에 대해 작동하는 루프 및 리디렉션이 포함됩니다.

#!/bin/sh
for file do
  tr -d '\r\t' <"$file" >"$file.safe"
done

옵션을 사용하면 -d지정된 tr문자를 제거합니다. 제거할 문자는 옵션이 아닌 첫 번째 인수로 함께 전달됩니다. 백슬래시 이스케이프를 사용 \n하여 개행(^J), \r캐리지 리턴(^M), \t탭(^I) 등의 특수 문자를 나타낼 수 있습니다 .

무의미하기 때문에 사용자에게 요청하는 코드를 재현하지 않았습니다. 어쨌든 디렉토리는 리디렉션으로 인해 오류를 일으키고 디렉토리를 일반 파일로 취급하는 등 무의미한 작업을 요청하지 않는 것이 실제로 호출자의 임무이므로 해당 부분도 건너뛰었습니다.

원본 파일을 바꾸려면 임시 파일에 쓴 다음 결과를 제자리로 옮깁니다.

#!/bin/sh
for file do
  tmp="$(TMPDIR=$(dirname -- "$file") mktemp)"
  tr -d '\r\t' <"$file" >"$tmp" && mv -f -- "$tmp" "$file"
done

임시 파일 이름은 mktemp스크립트가 강력하도록 를 사용하여 구성됩니다. 기존 파일을 덮어쓸 위험 없이 파일이 포함된 디렉터리에 대한 쓰기 권한이 있는 한 작동합니다. 다른 데이터를 삽입하려고 시도하는 다른 사용자가 해당 디렉토리에 쓸 수 있는 경우에도 안전합니다( 의 잠재적인 문제 /tmp).

mv명령은 호출이 성공한 경우에만 호출되므로 , 중간에 디스크가 꽉 차는 등의 이유로 실패 tr하더라도 데이터가 손실될 위험이 없습니다 .tr

파일에 특수 문자가 포함되어 있지 않은 경우 동일한 새 파일로 파일을 바꾸지 않으려면 다음 두 가지 방법이 있습니다.

  • 특수 문자를 먼저 확인할 수 있습니다. 이를 수행하는 방법에는 여러 가지가 있습니다. 한 가지 방법은 해당 특수 문자를 제외한 모든 문자를 제거하고 결과 문자 수를 계산하는 것입니다. 최적화로서 head -c 1특수 문자가 상단 근처에서 발견되면 전체 파일을 검토할 필요가 없도록 파이프를 통해 연결하십시오. 이렇게 하면 할 일이 없으면 개수가 0이고 그렇지 않으면 1입니다.

    if [ "$(tr -dc '\r\t' <"$file" | head -c 1 | wc -c)" -ne 0 ]; then
      tr -d '\r\t' <"$file" >"$tmp" && mv -f -- "$tmp" "$file"
    fi
    
  • 변환을 수행한 다음 원본과 동일한지 확인할 수 있습니다. 파일이 이미 원하는 상태인 경우가 많을 경우 속도가 느려질 수 있습니다. 반면에 이 기술은 파일이 원하는 상태에 있는지 확인하기가 쉽지 않은 경우에 일반화됩니다.

    tr -d '\r\t' <"$file" >"$tmp" &&
    if cmp -s "$tmp" "$file"; then
      rm -- "$tmp"
    else
      mv -f -- "$tmp" "$file"
    fi
    

답변2

스크립트 주위에 루프를 넣을 수 있습니다. 그래서:

 for c in "^I" "^M"; do
    for file; do
       if grep "$c" "$file"; then
          ...
          etc.
          ...
       fi
    done
 done

답변3

나는 이 펄 원 라이너를 선호합니다. '\cM'은 control-M 문자입니다. 원본 파일은 '.bak' 확장자로 백업됩니다. 이 확장자는 선택할 수 있습니다.

perl -i.bak -pe 's/\cM//g;'  file(s)

제거할 문자 클래스를 사용하는 예입니다. 괄호 안의 perl은 control-I와 control-M을 찾아 제거합니다. 하지만 이것을 정확히 테스트하지는 않았습니다.

perl -i.bak -pe 's/[\cM\cI]//g;' files(s)

답변4

사용할 생각을 해보셨나요?

 tr -d .....<characterlist>....

예를 들어 인쇄할 수 없는 문자를 제거하고 다른 파일에 넣으세요.

 cat filename | tr -cd '[:print:]' >/tmp/x.out

귀하의 응용프로그램에 맞게 문자 목록을 수정하십시오.... tr자세한 내용은 매뉴얼 페이지를 참조하십시오.

또한 정규식 범위가 허용되므로 좋습니다.

 echo '\001\002\003\004' | tr -d '[\001-\003]' | od -c

관련 정보