Unixスクリプトは、ファイルの最初の行を読み取った後に終了します。

Unixスクリプトは、ファイルの最初の行を読み取った後に終了します。

ファイル内の1行あたりのタブ数を計算し、条件が一致した場合は、その行を別のファイルに印刷しようとします。ただし、スクリプトは最初の行のみを読み取って終了します。

以下で何が問題なのか教えてください。

#!/bin/bash
set -e
set -o pipefail

filename="0101.tsv"
while IFS= read -r line;do

s=$(awk '{print gsub(/\t/,"")}')
echo $s

if [[ $s -eq 995 ]]; then
printf "%s\n" "$line"
continue
fi

done < $filename > abc.tsv

ありがとうございます! 。

答え1

ファイル内のタブで区切られたフィールドの数を計算したいようです。これを行うには、タブで入力行を分割して数を数える必要があります。 awkこれは自動的に行うことができ、結果フィールド数の特殊変数もありますNF

996フィールド(995ラベル)を含むすべての行を印刷したい場合:

awk -F '\t' 'NF == 996' <file

これは短縮された方法です。

awk 'BEGIN { FS = "\t" } NF == 996 { print }' <file

つまり、入力レコード(行)の印刷printを意味するのは、入力フィールド区切り記号です。print $0FS

ファイルからテキスト行を抽出し、それらをループ内の同様のツールに渡すか、それを通過するawkたびsedに常に同じ操作を実行するより効率的な方法があります。上記のコマンドはawk一度だけ呼び出されますが、ソリューション(データが正しく渡された場合)はファイル内のすべての行awkに対して呼び出されます。awk

答え2

@steeldriverのonelinerはこれをawk行うことができますが、bashシェルスクリプトで行を読むには、次のようにします。

#!/bin/bash

set -e
set -o pipefail

filename="0101.tsv"
while IFS= read -r line
do
 s=0
 len=${#line}
# echo "line=$line"
# echo "len=$len"
 for (( i=0; i<$len; i++ ))
 do
  if [ "${line:i:1}" ==  $'\t' ]
  then
   s=$((s +1))
  fi
 done
 echo $s

 if [[ "$s" == "995" ]]; then
  printf "%s\n" "$line"
  continue
 fi
done < "$filename" > abc.tsv

関連情報