web-dev-qa-db-ja.com

lsの出力からパターンに一致する数値を取得しますか?

フォルダがあり、その中でlsを実行すると、出力されます

t-1-myFirstTest.c
myFile.c
t-42-my_second_test.c
t-3-test1234.c
  .
  .
  .
mySecondFile.c
t-21-tset241.c

改行とt-と2番目の-の間の数字を除いて、このテキストのすべてを削除したいと思います。したがって、この前の出力は次のようになります。

1
42
3
 .
 .
 .
21

私には解決策がありますが、それは本当に悪いと思います。私たちが話しているフォルダーが実際には現在のディレクトリにある場合、私は

ls | grep -o -E t-[0-9]+-[a-zA-Z0-9_]+.c | grep -o -E t-[0-9]+ | grep -o -E [0-9]+

同じことを達成するためのより良い方法はありますか?

5
Garmekain

lsの出力を解析することは悪い考えです(lsの出力は厳密に見るためのものです)。詳細については、質問「 なぜ `ls`を解析しない*のですか? "」を参照してください。

これは、/bin/shでそれを行う方法です。

for filename in t-*-*.c; do
    [ ! -f "$filename" ] && continue
    number=${filename#t-}   # remove "t-" from start of filename
    number=${number%%-*}    # remove everything from first "-" in what remains
    printf '%s\n' "$number"
done

これは、名前がパターンt-*-*.cに一致する現在のディレクトリ内のすべてのファイル名を反復します。これらの名前のそれぞれについて、t-ビットが最初から削除され、次に2番目の-とその後のすべてが、別のパラメーター展開で削除されます。

展開${variable#Word}は、$variablestartからWordの(最短の)一致を削除しますが、 ${variable%%Word}は、文字列のendからWordの(最長の)一致を削除します。

bashでは、ファイル名に正規表現の一致を使用します。

for filename in t-*-*.c; do
    [ ! -f "$filename" ] && continue
    if [[ "$filename" =~ ^t-([0-9]+)- ]]; then
        printf '%s\n' "${BASH_REMATCH[1]}"
    fi
done

これは、各ファイル名のt-の後の数字と一致してキャプチャします。キャプチャされた数字のグループは、一致が成功した後、${BASH_REMATCH[1]}で使用できます。インデックス1は、正規表現の最初のキャプチャグループ(括弧)を参照します。

遅いが、おそらく快適な(「使い慣れた」のような)ソリューションの場合、外部コマンドを呼び出して、関心のある文字列のビットを解析することをお勧めします。

for filename in t-*-*.c; do
    [ ! -f "$filename" ] && continue
    cut -d '-' -f 2 <<<"$filename"
done

これはbashを想定しており、ループでcutを呼び出しても問題ないことを前提としています。これは、シェル自体に組み込まれた操作を使用するよりもはるかに遅くなります。ここでのcutコマンドは、bashから渡された文字列から2番目の--区切りフィールドを返すように求められます(「here-string」リダイレクトを使用)。

3
Kusalananda

あなたの出力によると:

ls|awk -F"-" '{print $2}'

動作するはずですが、考慮したい場合はt-一部の場合

ls|grep ^t-|awk -F"-" '{print $2}'

または

ls|awk -F"t-" '{print $2}'|awk -F"-" '{print $1}'

3
YoMismo

あなたの例からファイルのリストを作成したとき、私のlsはそれらを次のようにソートします。

$ ls -1
myFile.c
mySecondFile.c
t-1-myFirstTest.c
t-21-tset241.c
t-3-test1234.c
t-42-my_second_test.c

その結果、以下のbash関数は、ファイルの改行と番号を同じ順序で出力します。

改行とt-と2番目の間の数字を除いてこのテキストをすべて削除したい-

これは、t-に一致しないファイル名は「改行を除いて削除する」必要があることを意味すると解釈しました。つまり、これらのファイル名には空白行を出力しますが、それ以外の場合はダッシュ間の数字を出力します。

lsnums ()
{
    for f in *
    do
        if [[ "$f" =~ t-([[:digit:]]+)- ]]; then
            printf '%s\n' "${BASH_REMATCH[1]}"
        else
            echo
        fi
    done
}

結果の出力は次のとおりです。

$ lsnums


1
21
3
42

... 2つの空白行は、t-ではなくmyで始まる最初のタイプのファイルに対応しています。

3
Jeff Schaller

それは簡単に行うことができます:

ls | cut -d '-' -f 2
1
paulplusx