여러 디렉터리의 파일에 sed 사용

여러 디렉터리의 파일에 sed 사용

여러 디렉터리에 여러 개의 파일이 있고 각 파일의 첫 번째 줄에 잘못된 날짜가 있습니다. sed와 for 루프가 포함된 스크립트를 작성하려고 합니다.

각 파일은 올바른 날짜로 구성된 자체 디렉토리에 있습니다. 예를 들어 파일이 ./2014/06/02/record1에 있을 수 있으며 첫 번째 줄의 날짜를 "2014/06/02"로 바꾸고 싶습니다.

많은 파일이 있으며 각각 고유한 디렉토리가 있습니다. sed와 for 루프를 사용하여 이를 어떻게 달성할 수 있나요?

답변1

모든 파일을 반복하려면 예를 들어 상위 디렉토리에 있고 2014파일 자체가 다음과 같이 호출된다고 가정합니다 record<something>.

for pathname in 20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record*
do
    if [ -f "$pathname" ]; then
        # ...
    fi
done

이 패턴은 20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record*언급한 모든 경로 이름과 일치하며, 2000에서 2099까지의 최상위 디렉토리만 있다고 가정합니다.

루프에서의 테스트는 $pathname값이 기존 일반 파일의 경로 이름(또는 해당 파일에 대한 심볼릭 링크)인지 확인하는 것입니다. 패턴이 아무것도 일치하지 않으면 기본적으로 확장되지 않은 상태로 유지됩니다(대부분의 셸에서). 테스트를 통해 이 사실이 드러날 것입니다.

$pathname위 루프에서 디렉터리 경로를 얻으려면:

dirpath=$( dirname "$pathname" )

또는

dirpath=${pathname%/*}

dirname유틸리티는 지정된 경로 이름에 대한 디렉터리 경로인 문자열을 반환합니다. 이 변수 대체 변형은 마지막 변수 /의 모든 것을 제거합니다 $pathname. 이 경우 두 명령 모두 동일한 결과를 생성하지만 사용하는 것이 일반적으로 더 안전합니다(변수 대체가 반환되는 것이 아니라 주어진 문자열을 dirname반환함 ).aa/b/a/b

at 파일의 첫 번째 줄을 $pathnamein 문자열로 바꾸려면 $dirpath(GNU sed및 내부 편집 사용):

sed -i -e '1c\' -e "$dirpath" "$pathname"

cin 명령은 sed내용 줄을 완전히 삭제하고 그 자리에 다른 내용을 삽입합니다. 여기서는 첫 번째 행에만 적용하고 $dirname경로 이름의 날짜가 될 결과 문자열을 삽입합니다.

이것을 스크립트에 통합하십시오.

#!/bin/sh

for pathname in 20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record*
do
    if [ -f "$pathname" ]; then
        dirpath=${pathname%/*}
        sed -i -e '1c\' -e "$dirpath" "$pathname"
    fi
done

파일의 백업 복사본을 테스트합니다.


대체 동등한 구현 사용 (대부분 동일하며 일반 파일에 대한 심볼릭 링크인 파일을 find처리하지 않습니다 ):record*

find 20[0-9][0-9]/ -type f \
    -path '20[0-9][0-9]/[0-9][0-9]/[0-9][0-9]/record*' -exec sh -c '
    for pathname do
        sed -i -e "1c\\" -e "$( dirname "$pathname" )" "$pathname"
    done' sh {} +

이는 솔루션의 첫 번째 변형과 본질적으로 동일한 루프를 따릅니다.

답변2

다음 스크립트를 사용해 보세요.

#!/bin/bash

for YEAR in $(ls -1)
do
    echo -n Processing year $YEAR " "
    for MONTH in $(ls -1 $YEAR)
    do
        echo -n month $MONTH " "
        for DAY in $(ls -1 $YEAR/$MONTH)
        do
            echo -n day $DAY
            sed -i "1 s#^.*#$YEAR/$MONTH/$DAY#" $YEAR/$MONTH/$DAY/record1
        done
    done
    echo " "
done

참고: 파일 트리 위의 디렉터리에 스크립트를 저장하고 다음과 같이 실행합니다.

~/tree-of-files $ ../change-dates.sh 
Processing year 2014  month 06  day 02   
Processing year 2017  month 06  day 02 
Processing year 2018  month 06  day 02 
Processing year 2033  month 06  day 02 
~/tree-of-files $ 

답변3

기존 접근 방식은 약간 다릅니다. 각 파일에서 YYYY/MM/DD 디렉터리 형식을 가정하는 와일드카드 패턴을 사용하여 파일을 반복하고, 다음을 ed사용하여 첫 번째 줄을 디렉터리 구조를 포함하는 해당 이름으로 변경합니다.

for file in [0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]/*
do
  [ -f "$file" ] || continue
  ed -s "$file" <<< $'1c\n'"${file%/*}"$'\n.\nw\nq'
done

명령은 ed다음 구성 요소와 함께 이 문자열로 제공됩니다.

  • 1c-- 라인 1을 다음으로 변경합니다...
  • ${file%/*}-- 마지막 슬래시 이후에 생성된 변수의 매개변수 확장을 제거합니다 file(타임스탬프/디렉토리 구조 부분만 유지됨).
  • .--hange c명령 종료
  • w--디스크에 파일 쓰기
  • q——편집 종료

관련 정보