空の変数を検出するための文字列置換?

空の変数を検出するための文字列置換?

ファイルを繰り返していくつかの操作を実行するスクリプトがあります。文字列の置き換え日付を挿入してください。

#!/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

つまり(.*/)?、スラッシュで終わるオプションのパスです。[^/.]+- ファイル名の初期部分です(\.[^/]+)?

関連情報