빈 변수를 감지하기 위한 문자열 대체?

빈 변수를 감지하기 위한 문자열 대체?

파일을 반복하고 일부 작업을 수행하는 스크립트가 있습니다.문자열 교체날짜를 삽입하세요.

#!/bin/bash
f="/tmp/file.txt" # with .txt extension
timestamp="$(date +%H%M%S)"
echo "${f%%.*}-$timestamp.${f#*.}"

다음과 같은 결과가 출력됩니다. 이는 올바른 것입니다.

/tmp/file-220304.txt

그러나 파일에 확장자가 없으면 스크립트가 중단됩니다.

#!/bin/bash
f="/tmp/file" # no extension
timestamp="$(date +%H%M%S)"
echo "${f%%.*}-$timestamp.${f#*.}"
$ ./test.sh
/tmp/file-220359./tmp/file

${f:-not found}공백을 채우기 위해 정의되지 않은 경우와 같은 것을 사용할 수 있습니까 ? f아래 방법으로는 위의 문제를 어떻게 해결하는지 모르겠습니다.

#!/bin/bash
f="/tmp/file" # no extension
timestamp="$(date +%H%M%S)"
echo "${f%%.*}-$timestamp.${f#*.:-not found}"

결과:

$ ./test.sh
/tmp/file-221420./tmp/file

답변1

/tmp/dir.d/file파일 문제 도 발생합니다 .

그리고 zsh:

#! /bin/zsh -
f="/tmp/file.txt" # with .txt extension
timestamp=${(%):-%D{%H%M%S}}

set -o extendedglob
extension=${(M)f%.[^./]#}
print -r -- ${f%$extension}-$timestamp$extension

표준 sh구문을 사용하십시오(bash/zsh에서도 작동함):

#! /bin/sh -
f="/tmp/file.txt" # with .txt extension
timestamp=$(date +%H%M%S)

case ${f##*/} in
  (*.*) printf '%s\n' "${f%.*}-$timestamp.${f##*.}";;
  (*)   printf '%s\n' "$f-$timestamp";;
esac

를 사용하면 명령 실행을 피하기 위해 로 bash바꿀 수 있습니다 .timestamp=$(date +%H%M%S)printf -v timestamp '%(%H%M%S)T'date

답변2

간단한 솔루션을 원할 경우 다소 우아하지 않지만 실행 가능한 솔루션의 데모는 다음과 같습니다.

#!/bin/bash

# Test cases
FILE="/tmp/file"
# FILE="/tmp/file."
# FILE="/tmp/file.txt"
# FILE="/tmp/file.txt."

# TIMESTAMP="$(date +%H%M%S)"
printf -v TIMESTAMP '%(%H%M%S)T'

echo "${FILE%%.*}-${TIMESTAMP}.$([[ $FILE =~ \..*$ ]] && { echo "${FILE#*.}"; } || { echo "txt"; })"

.txt확장자가 없으면 위의 내용이 파일 이름에 추가됩니다.

확장자가 누락된 경우 기본 확장자를 파일 이름에 추가하지 않으려면 다음 코드 줄을 사용하십시오.

echo "${FILE%%.*}-${TIMESTAMP}$([[ $FILE =~ \..*$ ]] && { echo ".${FILE#*.}"; })"

답변3

단순화를 위해

#!/bin/bash
f="/tmp/file"
timestamp="$(date +%H%M%S)"
out="${f}-${timestamp}";
[ "${f%.*}" != "${f##*.}" ] && out="${f%.*}-${timestamp}.${f##*.}";
echo "$out"

.길을 안전하게 만들어라

dir=${f%/*};
file=${f##*/};
name=${file%.*};
suffix=${file##*.};
[ "$dir" != "$file" ] && dir=${dir}/ || unset dir;
[ "$name" != "$suffix" ] && suffix=.${suffix} || unset suffix;
echo "${dir}${name}-${timestamp}${suffix}"

줄 바꿈을 연속으로 제거해야 하는 경우
다음을 참고하세요. 고유한지 확인하기 위해 전체 타임스탬프(날짜 + 시간)를 사용하는 것이 좋습니다.

답변4

정의 되지 않은 것이 아니라 f첫 번째 점이 삭제되기 전 해당 부분의 값입니다 ${f#*.}. f점이 없으면 ${f#*.}와 마찬가지로 아무것도 삭제되지 않습니다 $f. 게다가 일치하기 때문에첫 번째./foo.txt포인트, 당신은 (it give) 와 같은 경로 문제를 갖게 될 것입니다 -181548./foo.txt.

점으로 구분된 접미사 없이 비어 있게 되는 ${f#*.}같음 $f또는 이와 유사한 것을 테스트해야 합니다 . ${f#${f%.*}}이에 따라 ${f%.${f##*.}}여전히 문제가 다시 발생합니다 ./file.

질문은 ./file먼저 경로에서 파일 이름 부분을 분할한 다음 거기서부터 계속하는 것을 제안합니다.

또 다른 방법은 정규식을 사용하는 것입니다. 이것은 내가 테스트한 파일 이름에 적용됩니다.

#!/bin/bash
f=$1
timestamp="$(date +%H%M%S)"
re='^((.*/)?[^/.]+)(\.[^/]+)?$'
if [[ $f =~ $re ]]; then
    echo "${BASH_REMATCH[1]}-${timestamp}${BASH_REMATCH[3]}"
fi

(.*/)?, 슬래시로 끝나는 선택적 경로입니다. [^/.]+- 파일 이름의 초기 부분입니다 (\.[^/]+)?.

관련 정보