bashスクリプトでファイル名をパラメータとして扱い、0、1、または2つのパラメータを入力および出力ファイル名として使用する、より明確で柔軟な方法が必要です。
- args = 0 の場合、stdin から読み込み、stdout に書き込みます。
- args = 1の場合、$ 1から読み込み、stdoutに書き込みます。
- args = 2の場合、$ 1から読み込み、$ 2を書き込みます。
Bashスクリプトのバージョンをより明確で短くするにはどうすればよいですか?
これが私が今持っているものです。動作しますが、きれいではありません。
#!/bin/bash
if [ $# -eq 0 ] ; then #echo "args 0"
fgrep -v "stuff"
elif [ $# -eq 1 ] ; then #echo "args 1"
f1=${1:-"null"}
if [ ! -f $f1 ]; then echo "file $f1 dne"; exit 1; fi
fgrep -v "stuff" $f1
elif [ $# -eq 2 ]; then #echo "args 2"
f1=${1:-"null"}
if [ ! -f $f1 ]; then echo "file $f1 dne"; exit 1; fi
f2=${2:-"null"}
fgrep -v "stuff" $f1 > $f2
fi
Perlのバージョンはよりきれいです。
#!/bin/env perl
use strict;
use warnings;
my $f1=$ARGV[0]||"-";
my $f2=$ARGV[1]||"-";
my ($fh, $ofh);
open($fh,"<$f1") or die "file $f1 failed";
open($ofh,">$f2") or die "file $f2 failed";
while(<$fh>) { if( !($_ =~ /stuff/) ) { print $ofh "$_"; } }
ベストアンサー1
もっと使いますI/O リダイレクト:
#!/bin/bash
[[ $1 ]] && [[ ! -f $1 ]] && echo "file $1 dne" && exit 1
[[ $1 ]] && exec 3<$1 || exec 3<&0
[[ $2 ]] && exec 4>$2 || exec 4>&1
fgrep -v "stuff" <&3 >&4
説明する
[[ $1 ]] && [[ ! -f $1 ]] && echo "file $1 dne" && exit 1
入力ファイルがコマンドライン引数として指定されているかどうか、およびファイルが存在するかどうかをテストします。
[[ $1 ]] && exec 3<$1 || exec 3<&0
設定されている場合
$1
、つまり入力ファイルが指定されている場合は、指定されたファイルがファイル記述子で開き、3
そうでない場合はstdin
ファイル記述子で繰り返されます3
。[[ $2 ]] && exec 4>$2 || exec 4>&1
同様に
$2
設定されている場合、つまり出力ファイルが指定されている場合、指定されたファイルはファイル記述子で開き4
、それ以外の場合はstdout
ファイル記述子で繰り返されます4
。fgrep -v "stuff" <&3 >&4
最後に
fgrep
呼び出され、それと以前に設定されたファイル記述子とstdin
それぞれにリダイレクトされます。stdout
3
4
標準入力と出力の再オープン
中間ファイルディスクリプタを開かない場合は、そのstdin
ファイルディスクリプタを指定された入力ファイルと出力ファイルに直接置き換えることができますstdout
。
#!/bin/bash
[[ $1 ]] && [[ ! -f $1 ]] && echo "file $1 dne" && exit 1
[[ $1 ]] && exec 0<$1
[[ $2 ]] && exec 1>$2
fgrep -v "stuff"
このアプローチの欠点は、スクリプト自体の出力とリダイレクト先のコマンドの出力を区別できないことです。元の方法では、スクリプト出力を変更されていないstdin
sum として指定できました。stdout
これは最終的にスクリプト呼び出し元によってリダイレクトされた可能性があります。指定された入出力ファイルはスクリプトstdin
とstdout
。