경로에서 추가 "./"를 제거하려면 어떻게 해야 합니까?

경로에서 추가 "./"를 제거하려면 어떻게 해야 합니까?

다음 스크립트를 고려해보세요 compare_times.sh(감사합니다.http://superuser.com/a/1780500):

#!/bin/bash
# Syntax: compare_times.sh directory_1 directory_2
# Semantics: for pairs of files with the same path at any depth in both directory_1 and directory_2, compare the file modification times and, if they differ, say which of the two files is older.
case "$2" in
    /*)
        # $2 is an absolute path
        cd $1
        find . -type f -exec bash -c "if [[ -f \"{}\" && -f \"$2/{}\" ]]; then if (cmp -s \"{}\" \"$2/{}\") then if [[ \"{}\" -ot \"$2/{}\" ]]; then echo \"$1/{} is older than $2/{}\"; else if [[ \"$2/{}\" -ot \"{}\" ]]; then echo \"$2/{} is older than $1/{}\"; fi; fi; fi; fi" \;;;
    *)
        # $2 is a relative path
        WORKING_DIR=$PWD
        cd $1
        find . -type f -exec bash -c "if [[ -f \"{}\" && -f \"$WORKING_DIR/$2/{}\" ]]; then if (cmp -s \"{}\" \"$WORKING_DIR/$2/{}\") then if [[ \"{}\" -ot \"$WORKING_DIR/$2/{}\" ]]; then echo \"$1/{} is older than $2/{}\"; else if [[ \"$WORKING_DIR/$2/{}\" -ot \"{}\" ]]; then echo \"$2/{} is older than $1/{}\"; fi; fi; fi; fi" \;
esac

계산 시간과 경로 이름의 잠재적인 허점을 제외하면 스크립트가 잘 작동하는 것 같습니다. 그러나 출력은 중복됩니다 ./.

$ pwd
/tmp
$ ls --full-time ad bd | cut -d ' ' -f 6-
ad:

2023-05-14 15:38:02.707216583 +0200 f

bd:

2023-05-14 15:38:06.835165122 +0200 f
$ compare_times.sh ad bd
ad/./f is older than bd/./f
$ compare_times.sh /tmp/ad bd
/tmp/ad/./f is older than bd/./f
$ compare_times.sh ad /tmp/bd
ad/./f is older than /tmp/bd/./f
$ cd ad
$ compare_times.sh . ../bd  
././f is older than ../bd/./f
$ compare_times.sh . /tmp/bd
././f is older than /tmp/bd/./f
$ cd ../bd
$ compare_times.sh ../ad .
../ad/./f is older than ././f
$ compare_times.sh /tmp/ad .
/tmp/ad/./f is older than ././f

./출력을 정리하고 더 쉽게 읽을 수 있도록 하려면 어떻게 해야 합니까 ? 예를 들어 위에서 실행한 명령의 경우 예상되는 출력은 다음과 같아야 합니다.

$ compare_times.sh ad bd
ad/f is older than bd/f
$ compare_times.sh /tmp/ad bd
/tmp/ad/f is older than bd/f
$ compare_times.sh ad /tmp/bd
ad/f is older than /tmp/bd/f
$ cd ad
$ compare_times.sh . ../bd      
f is older than ../bd/f
$ compare_times.sh . /tmp/bd
f is older than /tmp/bd/f
$ cd ../bd
$ compare_times.sh ../ad .
../ad/f is older than f
$ compare_times.sh /tmp/ad .
/tmp/ad/f is older than f

답변1

정말 나쁜 코드입니다.

이를 더 쉽게 읽고 이해하기 위한 첫 번째 단계는 이를 두 개의 스크립트로 분할하는 것입니다. 하지만 단 하나의 스크립트로도 수행할 수 있습니다.

#! /bin/bash -

if [[ "$#" -eq 2 ]]; then

    [[ -d "$1" && -d "$2" ]] || exit 2

    scriptpath="$(realpath -- "$0")"
    d1_path="$(realpath -- "$1")"
    d2_path="$(realpath -- "$2")"
    PWD_ORI="$(realpath -- "$PWD")"
    cd -- "$d1_path" || exit 1
    find . -type f -exec "$scriptpath" "$d1_path" "$d2_path" {} "$PWD_ORI" \;

elif [[ "$#" -eq 4 ]]; then

    [[ -d "$1" && -d "$2" && -f "$3" ]] || exit 2

    d1_path="$1"
    d2_path="$2"
    file_relpath="$3"
    file_relpath="${file_relpath#./}"
    f1_path="${d1_path}/${file_relpath}"
    f2_path="${d2_path}/${file_relpath}"
    PWD_ORI="$4"

    if [[ -f "$f1_path" && -f "$f2_path" ]]; then
        if cmp -s -- "$f1_path" "$f2_path"; then
            if   [[ "$f1_path" -ot "$f2_path" ]]; then
                printf '%s\n' "'${f1_path#"$PWD_ORI"}' is older than '${f2_path#"$PWD_ORI"}'"
            elif [[ "$f2_path" -ot "$f1_path" ]]; then
                printf '%s\n' "'${f2_path#"$PWD_ORI"}' is older than '${f1_path#"$PWD_ORI"}'"
            fi
        fi
    fi
fi

답변2

zsh로 전환하는 것이 옵션인 경우 동일한 접근 방식을 사용하는 것이 더 쉽고 안정적입니다.

#! /bin/zsh -
f1=( ${1?}/**/*(ND.) )  f2=( ${2?}/**/*(ND.) )
f1=( ${f1#$1/}       )  f2=( ${f2#$2/}       )

for f in ${f1:*f2}; do
  f1=$1/$f f2=$2/$f
  if cmp -s -- $f1 $f2; then
    if [[ $f1 -ot $f2 ]]; then
      print -r -- ${(q+)f1} is older than ${(q+)f2}
    elif [[ $f2 -ot $f2 ]]; then
      print -r -- ${(q+)f2} is older than ${(q+)f1}
    fi
  fi
done

답변3

죄송합니다. 메서드가 너무 많은 것을 좋아하지 않습니다 -exec. 개체가 정렬된 프로세스에 있고 먼저 수집(이름, 크기, 연령)된 다음 논리가 도입되는 배치 스타일 접근 방식을 보여 드리겠습니다. 다음 코드를 사용하면 출력이 보기 좋게 인쇄되거나 onlywould cp "$2/$1" "$3/$1", differwould overwrite , olderwould touch 및 willignore 와 같은 임시 함수 이름을 사용하여 same인터프리터에 제공될 준비가 됩니다.

cmp문자 대역폭은 모든 파서를 방해할 수 있으며 이는 인터페이스(일반적으로 호출) 구문 분석이 필요한 모든 솔루션 스타일에서 심각한 문제입니다. 주입 및 문자 대역폭에 대한 높은 표준을 통해 zsh대체 답변에 표시된 문자열 처리에 깊은 인상을 받았습니다.

#!/bin/bash
# <$1: mandatory directory
# <$2: mandatory directory
# <$FS: optional separator (default ";")
# <$RS: optional separator (default "\n")
# >stdout: differ|older|same|only relative_path directory directory
[ -d "$1" ] && [ -d "$2" ] && [[ "$1" != "$2" ]] || exit 8
FS="${FS:-;}"
RS="${RS:-$'\n'}"
(
  find "$1" -type f -printf "%T@$FS%s$FS$1$FS%P$RS";
  find "$2" -type f -printf "%T@$FS%s$FS$2$FS%P$RS";
) | # mod time ; size ; directory ; relative path
LC_COLLATE=C sort -t "$FS" -k4 -k1,1n |
awk 'NF!=4{ print "ERROR: lost parsing "FNR":"$0 >"/dev/stderr"
    exit 8
  }
  function alter(dir) { return (dir == d1 ? d2 : d1) }
  function quote(s){ return SQ gensub(SQ,BQ,"g",s) SQ }
  # differ 'path' 'dir1' 'dir2' : older    in dir1 than in dir2 and have different content
  # older  'path' 'dir1' 'dir2' : older    in dir1 than in dir2 and have same content
  # same   'path' 'dir1' 'dir2' : same age in dir1 than in dir2 and have same content
  pname && pname == $4 {
    cmp = "cmp -s "quote(pdir"/"pname)" "quote(alter(pdir)"/"pname)
    print( (psize == $2 && !system(cmp)) ? (ptime == $1 ? "same" : "older") : "differ",
      quote(pname), quote(pdir), quote(alter(pdir)))
    pname = ""; next
  }
  # only  'path' 'dir1' 'dir2' : path exist in dir1 not    in dir2
  pname { print("only", quote(pname), quote(pdir), quote(alter(pdir)))
    pname = ""
  }
  END { if (pname) print("only", quote(pname), quote(pdir), quote(alter(pdir)))
  }
  { pname = $4; pdir = $3; psize = $2; ptime = $1;
  }
' d1="$1" d2="$2" FS="$FS" RS="$RS" OFS=" " SQ="'" BQ="'\\\\\\\\''"

동일한 접근 방식을 사용하지만 주입 기회가 더 적고 단일 존재 또는 차이점 감지가 없으면 fdupes위와 같은 파이프라인에서 정렬할 수 있는 연령 및 유사성을 포함하여 많은 정보를 수집합니다. 기능을 추가하려는 경우 수집된 다른 파일 시스템 정보를 편리한 형식으로 결합할 수 있습니다.

#!/bin/bash
# <$1: mandatory directory
# <$2: mandatory directory
# >stdout: "older" relative_path directory directory
[ -d "$1" ] && [ -d "$2" ] && [[ "$1" != "$2" ]] || exit 8
fdupes -q -t -r "$1" "$2" |
awk '
  !NF{same++; next} # similarity id
  NF > 1 && $1" "$2 ~ "....-..-.. ..:.." {
    sub(" "d1"/"," {D1} "); sub(" "d2"/"," {D2} ")
    printf(ORS"%06d %s", same,$0) 
    next}
  {printf("\\n%s",$0)} # newline in name    
' d1="$1" d2="$2" | LC_COLLATE=C sort -k5 -k2,3 |
# same yyyy-mm-dd HH:MM {D} name 
awk '
  function direc(dir) { return (dir == "{D1}" ? d1 : d2) }
  function alter(dir) { return (dir == "{D1}" ? d2 : d1) }
  pname && pname == $5 {
    if ( psame == $1 && ptime != $2" "$3 )
      print("older", pname, direc(pdir), alter(pdir))
    pname = ""; next
  }
  { pname = $5; pdir = $4; psame = $1; ptime = $2" "$3 } 
' d1="$1" d2="$2"

답변4

s/\/\.\//\//g/./sed(스트림 편집기)를 사용하여 출력 /의 모든 위치를 바꾸십시오.

compare_times.sh ad bd | sed -e  "s/\/\.\//\//g"

스크립트 내에서 sed를 적용하려면 스크립트 내의 bash 기능에서 작업을 수행해야 합니다.

function my_function(){
... previous script goes here ...
}
my_function $1 $2 | sed -e  "s/\/\.\//\//g"

관련 정보