スクリプトに、globまたはSTDINから指定された一連のファイル名(スペースが含まれている場合があります)を読み取り、それらを使用して処理を実行したいと思います。私はどちらの方法でも別々に読むことができましたが、それらを組み合わせることはできませんでした。
これは、コマンドラインからグロブを読み取ります。
for filename in "$@"; do
process_file "$filename"
done
そして、これはSTDINから読み取られます。
IFS=$'\n' read -d '' -r -a filenames
for filename in "${filenames[@]}"; do
process_file "$filename"
done
私が本当に望んでいるのは、どちらか一方から配列に読み込むことです。これにより、for filename in...
ループ全体を2回複製する必要がなくなります。これが明らかな場合は申し訳ありませんが、私はBASHを初めて使用します。
編集:与えられた場合は引数から読み取り、それ以外の場合はSTDIN
を待つのが最善だと思います。どうすればいいですか?
編集:OK、問題は私が思っていたものではありません。問題は、process_fileもユーザー入力を要求することです。 STDIN
からEOFまで読み取り、それを保存して、再度入力を求める方法はありますか?
xargs
からtransformSTDIN
(エントリが多く、コマンドラインバッファよりもはるかに大きい)からargumentsを使用できます。
または、次のようなものかもしれません。
if [ $# -gt 0 ] ;then
for filename in "$@" ; do
process_file "$filename"
done
else
IFS=$'\n' read -d '' -r -a filenames
for filename in "${filenames[@]}"; do
process_file "$filename"
done
fi
または両方:
IFS=$'\n' read -d '' -r -a filenames
for filename in "${filenames[@]}" "$@" ; do
process_file "$filename"
done
fi
または、このようなオプションを追加して、-l
は行引数のみを表し、STDIN
からの読み取り(待機)がないことを確認します。
case "$1" in
-l )
shift
for filename in "$@" ; do
process_file "$filename"
done
;;
* )
for filename in "${filenames[@]}" "$@" ; do
process_file "$filename"
done
;;
esac
(未検証!)
コマンドラインでファイル名を指定しない場合、テキスト処理ツールは従来、標準入力から入力を読み取ります。 $#
変数をテストすることにより、コマンドライン引数があるかどうかを確認できます。引数を渡さない場合、process_file
が標準入力から読み取ると仮定します。
if [ $# -eq 0 ]; then
process_file
else
for x; do
process_file "$x"
done
fi
または、process_file
に引数が必要な場合は、/dev/stdin
を渡して、標準入力から読み取ります。
if [ $# -eq 0 ]; then set /dev/stdin; fi
for x; do
process_file "$x"
done
コマンドライン引数がない場合に、標準入力からファイル名のリストを読み取るように要求しました。もちろんそれは可能ですが、それは珍しいのでお勧めしません。ユーザーは、他のほとんどのツールとは異なる規則を学ぶ必要があります。それにもかかわらず、これを行う1つの方法があります。
if [ $# -eq 0 ]; then
set -f # turn off globbing
IFS='
' # set newlines to be the only field separator
set -- $(cat)
set +f; unset IFS
fi
for x; do
process_file "$x"
done
これは私のために働きます:
for filename in ${*:-`cat`}; do
process_file "$filename"
done
${*:-`cat`}
最初にコマンドライン引数を展開します。これが定義されていない場合(bashパラメーター置換:-)、パイプからstdin
を使用します。
bash4.4
以上:
if [ "$#" -eq 0 ]; then
readarray -d '' args
set -- "${args[@]}"
fi
for arg do
something with "$arg"
done
これは、cygwin X11 gvimとwindows gvimの両方でファイルを安全に開くために私が書いたスクリプトです。それはシェルラッパーとして設計されており、これはあなたが望むことをする部分です:
if [ ${#} -ne 0 ]; then #if we have filenames as CLArgs...
[[ ! -z ${DEBUG} ]] && echo "Got arguments [${#}]:'${@}'"
for OFILE in "${@}"; do
[[ -h ${OFILE} ]] && OFILE="$(readlink -f "${OFILE}")"
[[ ${WINVIM} == true ]] && OFILE=$(cygpath -wal "${OFILE}")
echo "\"${VIMRUN}\" --servername GVIM $RT \"${OFILE}\""
"${VIMRUN}" --servername GVIM $RT "${OFILE}" &
RT="--remote-tab"
done
else #otherwise read from stdin safely and handle spaces...
while read OFILE; do
[[ -h ${OFILE} ]] && OFILE="$(readlink -f "${OFILE}")"
[[ ${WINVIM} == true ]] && OFILE=$(cygpath -wal "${OFILE}")
echo "\"${VIMRUN}\" --servername GVIM $RT \"${OFILE}\""
"${VIMRUN}" --servername GVIM $RT "${OFILE}" &
RT="--remote-tab"
done
fi