コマンドの置換: 改行に分割するがスペースに分割しない

コマンドの置換: 改行に分割するがスペースに分割しない

この問題をさまざまな方法で解決できることを知っていますが、bashの組み込み機能のみを使用してこの問題を解決する方法があるかどうか、そうでない場合は最も効率的な方法は何かを知りたいです。

次の内容を含むファイルがあります。

AAA
B C DDD
FOO BAR

私の言葉は、複数の行があり、各行には空白がある場合とない場合があります。このようなコマンドを実行したい

cmd AAA "B C DDD" "FOO BAR"

使ったらcmd $(< file)手に入れる

cmd AAA B C DDD FOO BAR

使ったらcmd "$(< file)"手に入れる

cmd "AAA B C DDD FOO BAR"

各行に1つのパラメータのみを処理させるにはどうすればよいですか?

答え1

持ち運べる:

set -f              # turn off globbing
IFS='
'                   # split at newlines only
cmd $(cat <file)
unset IFS
set +f

または、サブシェルを使用してIFSオプションの変更をローカライズします。

( set -f; IFS='
'; exec cmd $(cat <file) )

シェルは、二重引用符なしで変数またはコマンド置換の結果に対してフィールド分割とファイル名の生成を実行します。したがって、を使用してファイル名の生成をオフにし、フィールドを区切る改行のみを含めるようにset -fフィールド分割を構成する必要があります。IFS

bash または ksh 構成を使用すると大きな利点はありません。IFS関数をローカライズできますがset -f

Bashまたはksh93では、フィールドを複数のコマンドに渡す必要がある場合は、配列にフィールドを格納できます。アレイを構築するときは、サイズ変更を制御する必要があります。次に、"${a[@]}"単語ごとに1つずつ配列の要素を展開します。

set -f; IFS=$'\n'
a=($(cat <file))
set +f; unset IFS
cmd "${a[@]}"

答え2

一時配列を使用してこれを実行できます。

設定:

$ cat input
AAA
A B C
DE F
$ cat t.sh
#! /bin/bash
echo "$1"
echo "$2"
echo "$3"

配列を埋める:

$ IFS=$'\n'; set -f; foo=($(<input))

配列を使用して下さい:

$ for a in "${foo[@]}" ; do echo "--" "$a" "--" ; done
-- AAA --
-- A B C --
-- DE F --

$ ./t.sh "${foo[@]}"
AAA
A B C
DE F

一時変数なしでこれを行う方法はありません。変更がIFS重要でないcmd場合は次のとおりです。

$ IFS=$'\n'; set -f; cmd $(<input) 

それは行わなければなりません。

答え3

bashこれを行う正式な方法は次のとおりです。

unset args
while IFS= read -r line; do 
    args+=("$line") 
done < file

cmd "${args[@]}"

または、あなたのbashバージョンに以下が含まれている場合mapfile

mapfile -t args < filename
cmd "${args[@]}"

マッピングファイルと読み込み中にループと1行ループの間にある唯一の違い

(set -f; IFS=$'\n'; cmd $(<file))

前者は空行を空の引数に変換し、一方のライナーは空行を無視します。この場合、とにかく私は1行の動作を好むので、その簡潔さは2倍の利点です。

使用しますが、適用される前にコマンドラインを設定すると解釈されるため、IFS=$'\n' cmd $(<file)機能しません。$(<file)IFS=$'\n'

私の場合はうまくいきませんでしたが、今では多くのツールがnull (\000)代わりに行終了をサポートしていることがわかりましたnewline (\n)。これは、次のような場合の一般的な原因であるファイル名を処理するときに多くの操作を容易にします。

find / -name '*.config' -print0 | xargs -0 md5

ワイルドカードや補間、またはその他の操作なしで、md5に引数で正規化されたファイル名のリストを提供します。これにより、組み込まれていないソリューションが誕生しました。

tr "\n" "\000" <file | xargs -0 cmd

空行も無視しますが、空白のみの行はキャプチャします。

答え4

old=$IFS
IFS='  #newline
'
array=`cat Submissions` #input the text in this variable
for ...  #use parts of variable in the for loop
... 
done
IFS=$old

私が見つけるための最良の方法。正常な仕事。

関連情報