私のスクリプトは、globまたはSTDIN(スペースを含む)として提供された複数のファイル名を読み、それを使用して操作を実行したいと思います。 2つの方法を別々に読むことはできますが、組み合わせることはできません。
これはコマンドラインからglobを読み込みます。
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...
私が本当に望むのは、これらのうちの1つを配列に読み込んでループ全体を2回繰り返す必要がないようにすることです。これが明らかな場合は申し訳ありません。私はBASHを初めて使用します。
編集:最良の方法は、与えられたパラメータからそれを読み、そうでない場合は待つことですSTDIN
。どうすればいいですか?
編集:良いです。問題は私が考えたものとは異なります。問題は、process_fileにもユーザー入力が必要であることです。STDIN
EOFで読み取りを開始して保存し、再入力を要求する方法はありますか?
答え1
テキスト処理ツールは通常、コマンドラインにファイル名を指定しないと、標準入力から入力を読み込みます。変数をテストして、コマンドライン引数があるかどうかを確認できます$#
。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
コマンドライン引数なしで標準入力から読み取るファイル名のリストを要求しています。もちろん可能ですが珍しいのでお勧めできません。ユーザーは他のほとんどのツールとは異なる規則を学ぶ必要があります。それにもかかわらず、次の方法があります。
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
答え2
新しい回答2021-10-18
bash:以下からリストを生成します。ディスカッション そして/または 標準入力
次の小さなスクリプトを考えてみましょう。
#!/bin/bash
declare -a ARGS=("$@")
while read -rt .02 arg;do
ARGS+=($arg)
done
declare -p ARGS
電話でargsAndInput.sh
サンプルリクエストも可能です。
seq 1 10 | ./argsAndInput.sh foo bar baz
declare -a ARGS=([0]="foo" [1]="bar" [2]="baz" [3]="1" [4]="2" [5]="3" [6]="4" [
7]="5" [8]="6" [9]="7" [10]="8" [11]="9" [12]="10")
seq 1 10 | ./argsAndInput.sh
declare -a ARGS=([0]="1" [1]="2" [2]="3" [3]="4" [4]="5" [5]="6" [6]="7" [7]="8"
[8]="9" [9]="10")
./argsAndInput.sh foo bar baz
declare -a ARGS=([0]="foo" [1]="bar" [2]="baz")
./argsAndInput.sh
declare -a ARGS=()
必要に応じてタイムアウト(read -t .02
)を短くするか、次を使用できます。
while read -t 0 &&
read -r arg;do
ARGS+=($arg)
done
入力が準備されたと確信している場合今後バッシュを実行する必要があります。
古い回答
あなたはxargs
それを使用することができます切り替える STDIN
(項目が多くてもコマンドラインバッファよりはるかに大きいです)議論。
または、次のようなものかもしれません。
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
(検証されていない!)
答え3
これは、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
答え4
以上bash4.4
:
if [ "$#" -eq 0 ]; then
readarray -d '' args
set -- "${args[@]}"
fi
for arg do
something with "$arg"
done