次のエラーが発生しました:
./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
コメント
- 中かっこで何を達成しようとしていますか?変数も引用してください。
- を参照してください。find'の出力の悪い習慣をループするのはなぜですか?
回答
${ ... }
(中括弧)はいくつかをマークします一種のパラメータ拡張。最も単純なのは、変数の値を拡張することです。コードの中括弧内のものは、有効なパラメータ名やその他の展開ではないため、シェルは文句を言います。
代わりにコマンド置換が必要なようです。そのため、構文は(通常の括弧)。
また、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 ...
コメント
回答
${}
の代わりにバッククォートを使用`
[キーボードの[エスケープ]の下のボタン]
コメント
- しないでください'バックティックを使用します。コマンド置換を使用します。
$( ... )
- 古く、読みにくく、入れ子になっておらず、' 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を含み、シーケンス内の欠落ファイルを示します)。
<<<
がある場合は、おそらく${var/pat/repl}
もあります。 sedを実行する場合は、両方のルールを1つのsed
インスタンスに与えることができます:sed -e 's/assemblyDB\.//' -e 's/\.las//'