2つの拡張子を持つファイル名を解決するシェルスクリプト。両方の拡張子を持つファイルがある場合は、スクリプトを呼び出します。それ以外の場合は失敗します。

2つの拡張子を持つファイル名を解決するシェルスクリプト。両方の拡張子を持つファイルがある場合は、スクリプトを呼び出します。それ以外の場合は失敗します。

2つの拡張子(.txtと.ctl)を持つファイルがあるかどうかを確認し、ファイルに両方の拡張子がある場合はスクリプトを呼び出す必要があります。それ以外の場合、操作は失敗します。いくつか試してみましたが、期待どおりに動作しません。誰でも私を助けることができますか?

答え1

#!/bin/bash

# Assuming the directory is passed to us as an argument...
DIR="$1"
SCRIPT=/path/to/the/other/script.sh

COUNT=0
for i in "$DIR"/*.txt "$DIR"/*.ctl ;do
  if [ -f "$i" ] ;then # this is a regular file
    ((COUNT++))
    "$SCRIPT" "$i"
  fi
done

if [ $COUNT -eq 0 ] ;then
   exit 1 # No .txt or .ctl files were found.
fi

質問はあまり明確ではないので、特定のディレクトリ内のすべてのファイルにこれら2つの拡張子があることを確認したいとします。

答え2

正確に何を確認したいのかは明確ではありません。以下は、zshシェルで問題を解決するいくつかの方法です。

#! /bin/zsh -

for dir do
  txt=($dir/*.txt(ND:t:r))
  ctl=($dir/*.ctl(ND:t:r))
  both=("${(@)txt:*ctl}")
  txt_but_not_ctl=("${(@)txt:|ctl}")
  ctl_but_not_txt=("${(@)ctl:|txt}")

  print -r -- "$dir has $#txt file${txt[2]+s} with a .txt extension"
  print -r -- "$dir has $#ctl file${ctl[2]+s} with a .ctl extension"
  print -r -- "$#both .txt file${both[2]+s} in $dir have matching files with the same root name and a .ctl extension"
  print -r -- "$dir has $#txt_but_not_ctl .txt file${txt_but_not_ctl[2]+s} without a corresponding .ctl file"
  print -r -- "$dir has $#ctl_but_not_txt .ctl file${ctl_but_not_txt[2]+s} without a corresponding .txt file"

  (($#both && $#txt_but_not_ctl == 0 && $#ctl_but_not_txt == 0)) &&
    print -r -- "all the .txt files in $dir have a corresponding .ctl file and vis versa"
done

ここで関心のある主な構造は次のとおりです。

  • files=(*(DN)):パターンに一致するファイルのリストを配列変数に割り当てます。D隠しリストを含み、N空のリスト(nullglob)を許可します。
  • :t:r、選択する(目次セクションの削除)と拡張機能を削除してください。
  • ${A:*B}2 つの配列の交差点です。"${(@)A:*B}"空の要素を保持します(たとえば、.txtまたはというファイルがある場合.ctl)。
  • ${A:|B}2つの配列(A中央にない要素B)を減算します。
  • $#array:配列の要素数。
  • (( arithmetic expression ))算術式を評価して返します。本物結果がゼロでない場合。

最新のGNUベースのシステムを使用している場合は、次のことを行うことができますbash(もっと苦手で、難しく、効率が悪いですが)。

#! /bin/bash -
shopt -s nullglob dotglob

printz() {
  (($# == 0)) || printf '%s\0' "$@"
}

for dir do
  txt=("$dir"/*.txt)
  txt=("${txt[@]##*/}")
  txt=("${txt[@]%.*}")
  ctl=("$dir"/*.ctl)
  ctl=("${ctl[@]##*/}")
  ctl=("${ctl[@]%.*}")

  readarray -td '' both < <(
    LC_ALL=C comm -z12 <(printz "${txt[@]}" | LC_ALL=C sort -z) \
                       <(printz "${ctl[@]}" | LC_ALL=C sort -z))
  readarray -td '' txt_but_not_ctl < <(
    LC_ALL=C comm -z13 <(printz "${txt[@]}" | LC_ALL=C sort -z) \
                       <(printz "${ctl[@]}" | LC_ALL=C sort -z))
  readarray -td '' ctl_but_not_txt < <(
    LC_ALL=C comm -z23 <(printz "${txt[@]}" | LC_ALL=C sort -z) \
                       <(printz "${ctl[@]}" | LC_ALL=C sort -z))

  printf '%s\n' "$dir has ${#txt[@]} file${txt[2]+s} with a .txt extension"
  printf '%s\n' "$dir has ${#ctl[@]} file${ctl[2]+s} with a .ctl extension"
  printf '%s\n' "${#both[@]} .txt file${both[2]+s} in $dir have matching files with the same root name and a .ctl extension"
  printf '%s\n' "$dir has ${#txt_but_not_ctl[@]} .txt file${txt_but_not_ctl[2]+s} without a corresponding .ctl file"
  printf '%s\n' "$dir has ${#ctl_but_not_txt[@]} .ctl file${ctl_but_not_txt[2]+s} without a corresponding .txt file"

  ((${#both[@]} && ${#txt_but_not_ctl[@]} == 0 && ${#ctl_but_not_txt[@]} == 0)) &&
    printf '%s\n' "all the .txt files in $dir have a corresponding .ctl file and vis versa"
done

どこ:

  • NDグローバルnullglobdotglobオプションに置き換えられます。
  • :t"${array[@]##*/}"パターンストリッピングksh演算子の使用
  • :r"${array[@]%*/}"パターンストリッピングksh演算子の使用
  • 配列の結合と減算は、NULで区切られたレコードを持つCロケールでsort+を使用して実行されますcomm(NULは、ファイル名(またはbash変数)には見つからない唯一のバイトです)。

関連情報