パターンに基づいてサブディレクトリ名を抽出する

パターンに基づいてサブディレクトリ名を抽出する

シェル変数に保存されているパスのリストがありますtmp。たとえば、次のようになります。

/abc/bcd/def/ZRT834/ZRT834_9/5678/S1_L001_R1.tar
/abc/bcd/def/ZRT834/ZRT834_9/5678/S2_L001_I1.tar
/abc/bcd/def/ZRT834/ZRT834_9/5678/S1_L001_I2.tar
/abc/bcd/def/ZRT207/ZRT207_1/5678/S1_L001_R1.tar
/abc/bcd/def/ZRT207/ZRT207_1/5678/S1_L001_R2.tar
/abc/bcd/def/ZRT207/ZRT207_1/5678/S1_L001_I2.tar

パスの一致パターンに基づいて新しいディレクトリを作成したいと思います。上記の例では、ディレクトリをZRT834_9作成し、そのディレクトリのファイルへのZRT207_1ソフトリンクを作成したいと思います。tar

ZRT834_9私の出力は次S1_L001_R1.tarのようになりますS2_L001_I1.tarS1_L001_I2.tar

どうやってこれを達成できますか?

答え1

存在するzsh

files=(
  /abc/bcd/def/ZRT834/ZRT834_9/5678/S1_L001_R1.tar
  /abc/bcd/def/ZRT834/ZRT834_9/5678/S2_L001_I1.tar
  /abc/bcd/def/ZRT834/ZRT834_9/5678/S1_L001_I2.tar
  /abc/bcd/def/ZRT207/ZRT207_1/5678/S1_L001_R1.tar
  /abc/bcd/def/ZRT207/ZRT207_1/5678/S1_L001_R2.tar
  /abc/bcd/def/ZRT207/ZRT207_1/5678/S1_L001_I2.tar
)
# or files=(${(f)"$(<list.txt)"}) to get the file list from the non-empty
# lines of list.txt, or files=($=tmp) for word splitting the contents
# of a $tmp scalar variable according to the current value of $IFS.

for file ($files) {
  dir=${file:h5:t}
  mkdir -p -- $dir && ln -s -- $file $dir/
}

-comComponent1のヘッダーと結果の尾を${file:h5}取得する位置です。または最後から数えることができます。5h$file:t${file:t3:h1}


¹ここ要素パスコンポーネントです。たとえば、コンポーネントは、、、、および../a//b///c/./d/eです。与え、降伏する。 andを適用する前に、仕様への絶対パスの取得も参照してください。..abc.de:h5../a//b///c/.:t.${file:A:h5:t}:h5:t

答え2

あなたの説明に基づいて、次の仮定が行われました。

  • 変数tmpには、改行で区切られたファイル名のリストが含まれています。[1]
  • あなたは抽出したいファイル名のパス要素(たとえば、ZRT834_9およびZRT207_1
  • サブディレクトリがまだ存在しない場合は、このパス要素を使用してサブディレクトリを作成しようとします。
  • ファイル名を新しく作成されたディレクトリにシンボリックリンクしようとしています。
#!/bin/bash

tmp="/abc/bcd/def/ZRT834/ZRT834_9/5678/S1_L001_R1.tar
     /abc/bcd/def/ZRT834/ZRT834_9/5678/S2_L001_I1.tar
     /abc/bcd/def/ZRT834/ZRT834_9/5678/S1_L001_I2.tar
     /abc/bcd/def/ZRT207/ZRT207_1/5678/S1_L001_R1.tar
     /abc/bcd/def/ZRT207/ZRT207_1/5678/S1_L001_R2.tar
     /abc/bcd/def/ZRT207/ZRT207_1/5678/S1_L001_I2.tar"

while read -r f ; do
  d="$(echo "$f" | sed -E 's:^(/+[^/]+){4}/+([^/]*)/.*:\2:')"
  [ -z "$d" ]   && echo "Error: no fifth element in path: '$f'" && exit 1
  mkdir -p "$d" || exit 1
  ln -s "$f" "$d/"
done <<< "$tmp"

スクリプトsedは拡張正規表現(オプション)を使用し-E(ほぼ英語に翻訳されています)(最初の4つのグループ()をキャプチャグループ1としてキャプチャします(1つ以上のスラッシュの後に1つ以上のスラッシュ以外の文字が続く)。 。 1つ以上のスラッシュはキャプチャグループ2に入り、入力行全体をキャプチャグループ2()に置き換えます。{4}/+[^/]+[^/]+\2

「1つ以上のスラッシュ」は、このようなパス名が完全に有効であるためです/foo/////////////////bar////baz。追加/ sは無視されます。しかし、いくつかのプログラム(smbclient例:スタートサーバー名の前に2つのスラッシュを使用しますが、ほとんどのプログラムではそうではありません。

[1] これには配列を使用する必要があります。例えば

#!/bin/bash

# double-quote each array element even though your sample
# data doesn't need to be quoted - because other filenames
# might contain white-space or shell metacharacters.
tmp=("/abc/bcd/def/ZRT834/ZRT834_9/5678/S1_L001_R1.tar"
     "/abc/bcd/def/ZRT834/ZRT834_9/5678/S2_L001_I1.tar"
     "/abc/bcd/def/ZRT834/ZRT834_9/5678/S1_L001_I2.tar"
     "/abc/bcd/def/ZRT207/ZRT207_1/5678/S1_L001_R1.tar"
     "/abc/bcd/def/ZRT207/ZRT207_1/5678/S1_L001_R2.tar"
     "/abc/bcd/def/ZRT207/ZRT207_1/5678/S1_L001_I2.tar")

for f in "${tmp[@]}" ; do
  d="$(echo "$f" | sed -E 's:^(/+[^/]+){4}/+([^/]*)/.*:\2:')"
  [ -z "$d" ]   && echo "Error: no fifth element in path: '$f'" && exit 1
  mkdir -p "$d" || exit 1
  ln -s "$f" "$d/"
done 

答え3

GNU sedは代替構造のbacklinkパラメータを使用してシェルコマンドを実行できます。

sed 's%.*/\([^/]*/\)[^/]*/[^/]*%mkdir -p "\1";ln -s "&" "\1"%e;d' <<<"$tmp"

関連情報