$ {ls …を実行している不正な置換| sed …}とbash

次のエラーが発生しました:

./assemblyDB.116.las test.sh: line 9: ${ls $filename | sed "s/assemblyDB.//" | sed "s/.las//"}: bad substitution 

これはスクリプトです:

for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename no=${ls $filename | sed "s/assemblyDB.//" | sed "s/.las//"} echo $no done 

コメント

回答

${ ... }(中括弧)はいくつかをマークします一種のパラメータ拡張。最も単純なのは、変数の値を拡張することです。コードの中括弧内のものは、有効なパラメータ名やその他の展開ではないため、シェルは文句を言います。

代わりにコマンド置換が必要なようです。そのため、構文は(通常の括弧)。

また、ls $filename | sed...lsは少し見えます不要な場合、変数はファイル名に展開され、lsはそれを渡すだけです。代わりにecho "$filename" | sed ...を使用できます。

とはいえ、これらの変更はシェルで直接行うことができます:

no="${filename/assemblyDB.}" # remove first match no="${no/.las}" 

または、標準演算子を使用して:

no="${filename#assemblyDB.}" # remove from start of string no="${no%.las}" # remove from end of string 

sedを実行する場合、.は通常の任意の文字と一致することに注意してください。式なので、バックスラッシュで引用する方が正しいでしょう。また、1つのsedインスタンスに両方のコマンドsed -e "s/assemblyDB\.//" -e "s/\.las//"を指定することもできます。

そしてfor filename in $(find . -type f -name "assemblyDB.*.las"); doには、 lsの解析にあるすべての問題があります。ほとんどの場合、ファイル名の空白とワイルドカードによって問題が発生します。 ksh / Bash / zshでは、シェルでループ全体を実行できます。

shopt -s globstar # in Bash for filename in **/assemblyDB.*.las; do ... 

コメント

  • @Jesse_b、はい。ただし、シェルに<<<がある場合は、おそらく${var/pat/repl}もあります。 sedを実行する場合は、両方のルールを1つのsedインスタンスに与えることができます:sed -e 's/assemblyDB\.//' -e 's/\.las//'
  • UUOEを指摘します;)

回答

${}の代わりにバッククォートを使用` [キーボードの[エスケープ]の下のボタン]

コメント

  • しないでください'バックティックを使用します。コマンド置換を使用します。 $( ... )
  • 古く、読みにくく、入れ子になっておらず、' b>常に括弧コマンド置換に置き換えられます。さらに、ほとんどのマークダウン言語ではインラインコードブロックに配置するのが難しいです:)
  • そうです、そうです。しかし、この質問に関して、私の答えはどこで間違っていましたか??
  • バックティックの使用を提案しました。
  • @Jesse_bそこに'たくさんありますバックティックを使用しない理由のいくつかですが、それらをネストできないことはそれらの1つではありません:echo `echo \`echo hello\`` 。はい、エスケープする必要がありますが、それは'が$(...)ほど簡単にネストできないことを意味し、'不可能です。

回答

コマンドの置換(3行目)

for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename no=$(ls $filename | sed "s/assemblyDB.//" | sed "s/.las//") echo $no done 

は、すでに指摘したように、(3行目lsなし)

以下(4行目がなくなり、直接エコーするようになりました)

for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed "s/assemblyDB.//" | sed "s/.las//" done 

そしてsedコマンドを減らすことができますto(3行目)

for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed "s/assemblyDB.//;s/.las//" done 

またはsedで中央部分を抽出します:(まだ3行目)

for filename in $(find . -type f -name "assemblyDB.*.las"); do echo $filename echo $filename | sed -r "s/.*assemblyDB.(.*).las/\1/"" done 

for-iteratorではなくfind-iteratorになりました:(1行目から3行目、4行目がなくなりました)

find . -type f -name "assemblyDB.*.las" -printf "%f\n" -exec sh -c " echo {} | sed -r "s/.*assemblyDB.(.*).las/\1/"" ";" assemblyDB.11.las 11 assemblyDB.9.las 9 assemblyDB.10.las 10 

ファイル名がこのような順序または同様の順序では、次の順序でも機能する可能性があります。

for i in {8..12} ; do ls assemblyDB.$i.las && echo $i ; done 2>/dev/null assemblyDB.9.las 9 assemblyDB.10.las 10 assemblyDB.11.las 11 

(8と12を含み、シーケンス内の欠落ファイルを示します)。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です