次の構文を使用してファイル名を読み取り、拡張子を変更してデータファイルと一致する名前を生成します。たとえば、ABC_1.fastq.Blockxy、XYZ_1.fastq.Block34があり、ABC_2.fastq.Block12、XYZ_2.fastq.Block34を新しいファイル名として生成したいとします。
for infile in *_1.fastq.Block*
do
#base=$(basename ${infile} _1.fastq.**)
IFS='_'
read -ra ADDR <<< $infile
base=${ADDR[0]}
IFS='.'
read -ra ADDR <<< ${ADDR[1]}
second_file="${base}_2.fastq.${ADDR[2]}"
echo $second_file
done
実行すると、スクリプトが印刷されます。
ABC_2 fastq Block12
XYZ_2 fastq Block34
それがfastqとBlock12の間のスペースです。接続すると、なぜ3つの文字列の間にピリオドの代わりにスペースがありますか?変数名に中かっこを使用すると、この問題は解決されると思います。
答え1
存在する
echo $second_file
パラメータ拡張を引用するのを忘れたため、これは分割+グローブの影響を受けます。したがって、を使用すると、最初に、に分割され、IFS=.
各ABC_2.fastq.Block12
単語ABC_2
はグローブの影響を受けます。どの単語にもグロップ演算子が含まれていないため、ここでは効果はありません。fastq
Block12
したがって、3つのパラメータが渡され、echo
印刷スペースが区別されます。
変数の内容と改行文字を印刷するには、次のものが必要です。
printf '%s\n' "$var"
詳細については、次を参照してください。
次に、コードにいくつかのコメントを追加します。
zsh
Bashには同等のglob(N)
修飾子やksh93のglob演算子がないため、~(N)
forループでglobを使用する前に(少なくとも)次のオプションを設定する必要がありますnullglob
。shopt -s nullglob for infile in *_1.fastq.Block*; do...
これを行わずに一致するファイルがない場合は、テキストを繰り返します。
*_1.fastq.Block*
次の方法でのみIFSを設定できます
read
(以前のバージョンで必要な引用符を参照IFS=_ read -ra ADDR <<< "$infile"
)。これは実行時にのみ変更され、戻り後は前の値に戻ります。$infile
bash
$IFS
read
read
IFS=. read -ra <<< "$var"
分けるのはひどい方法です。 Firstは1行でのみ機能します$var
。これは必ずしもファイル名ではなく、非常に非効率的です。これには、内容を$var
一時ファイルに保存するか、bash
バージョンおよび/またはサイズに従ってパイプし、改行文字が見つかる$var
まで一度に1バイトずつ読み込むことが含まれます。ここでは、代わりに分割+グローブ演算子を使用できます。
IFS=:; set -o noglob addr=( $infile )
addr=( $infile'' )
(またはいいえ末尾を無視します:
。 )または、適切な分割演算子を使用してより良いシェルに切り替えます。
別のアプローチは次のとおりです。
regex='^(.*)_1\.fastq\.(Block.*)$' if [[ $infile =~ $regex ]]; then outfile=${BASH_REMATCH[1]}_2.fastq.${BASH_REMATCH[2]} ...
正規表現の一致は有効なテキストでのみ機能しますが、これは再びファイル名を保証しません。
ここでは、標準
sh
パラメトリック拡張演算子を使用することもできます。new_file=${infile%_1.fastq.Block*}_2.fastq.Block${infile##*_1.fastq.Block}
またはksh93スタイル:
new_file=${infile/_1.fastq.Block/_2.fastq.Block}
_1.fastq.Block
(ファイル名が複数回表示される場合は、これらすべての方法間で動作に違いがあることに注意してください。)
1 ただし、a が実行時に処理trap
されると、read
このトラップのコードが変更されます。$IFS