このようなテキストを含む.txtファイルがあります
A1/B1/C1
A2/B2/C2
A3/B3/C3
各行の.txtファイルを読み取り、最初のWord(A1、A2、A3)に基づいてディレクトリを作成するスクリプトが必要です
次のようなスクリプトを作成しました。
file="test.txt"
while IFS='' read -r line
do
name="line"
mkdir -p $line
done <"$file"
実行中にディレクトリA1が作成され、次にサブディレクトリB1およびC1も作成されます。同じことが別の行(A2 *およびA3 *)でも発生します
A1、A2、A3ディレクトリのみを作成するにはどうすればよいですか?
「/」文字を含むA1/B1/C1のような名前を作りたくありません。 「/」文字の前にWordを取り、ディレクトリ名にしたいだけです。ちょうど「A1」「A2」「A3」。
各行の1
stスラッシュ-cut
elimitedフィールドだけをd
して、リストをmkdir
に渡すことができます。
mkdir $(<dirlist.txt cut -d/ -f1)
$ cat dirlist.txt
A1/A2/A3
B1/B2/B3
C1/C2/C3
$ ls
dirlist.txt
$ mkdir $(<dirlist.txt cut -d/ -f1)
$ ls
A1 B1 C1 dirlist.txt
リストにhuge個のディレクトリ名が含まれている場合、 ARG_MAX の問題が発生する可能性があります。この場合はGNU parallel
またはxargs
は次のとおりです。
parallel mkdir :::: <(<dirlist.txt cut -d/ -f1)
xargs -a<(<dirlist.txt cut -d/ -f1) mkdir
parallel
でカバーされていますが、ディレクトリ名にスペースが含まれている場合、xargs
のアプローチは機能しません。行区切り文字として\0
を使用するか、単にxargs
に改行文字のみを入力するように指示することができます- Martin Bonner )代わりに:
xargs -0a<(<dirlist.txt tr \\{n,0} | cut -d/ -f1 -z) mkdir # \\{n,0} equals \\n \\0
xargs -d\\n -a<(<dirlist.txt cut -d/ -f1) mkdir
いずれかのフィールドに改行文字が含まれている場合、「真の」行末を識別し、それらの改行文字のみをたとえば\0
。これはawk
の場合ですが、ここでは取得しすぎだと感じています。
read
にIFS='/'
を設定し、最初の各フィールドを個別の変数first
に割り当て、残りのフィールドを変数rest
に割り当てて、最初のフィールドの値を操作する必要があります。 (または、単一の配列にread -ar array
を使用し、最初のフィールドの値に"${array[0]}"
を使用できます。)
while IFS='/' read -r first rest;
do
echo mkdir "$first"
done < test.txt
<test.txt xargs -d'\n' -n1 sh -c 'echo mkdir "$'{1%%/*}'"' _
<test.txt xargs -d'\n' bash -c 'echo mkdir "$'{@%%/*}'"' _
ANSI-C引用符$'...'
は、特殊文字を含むディレクトリ名を処理するために使用されます。
末尾の_
(任意の文字または文字列)はbash -c '...'
に対してargv [0]になり、$@
には1から始まる残りのパラメーターが含まれます。これがないと、2番目のコマンドでmkdir
への最初のパラメーターが失われます。
${1%%/*}
で Shell(POSIX sh/bash/Korn/zsh)パラメーター置換展開 を使用して、スラッシュに続く可能な限り長い一致を削除します。 xargsによって読み取られた行;
追伸:
echo
の前にあるmkdir
を削除して、これらのディレクトリを作成します。-d'\n'
ewlineの代わりにNUL文字で区切られている場合は、-0
を\n
に置き換えます(ディレクトリ名に改行が埋め込まれている場合)。test.txt
の内容:
A 12"x4" dir/B b/C c
A1/B1/C1
A2/B2/C2
A3/B3/C3
A[123]
フォルダーを作成するスクリプト:
file="test.txt"
while read -r line ; do
mkdir "${line%%/*}"
done < "$file"
ls
の出力:
A 12"x4" dir
A1
A2
A3
質問の入力例に示されているような単純なケースでは、cut
を使用し、mkdir
を介してxargs
に出力を渡すだけです。
cut -f1 -d '/' file.txt | xargs -L1 mkdir
ディレクトリ名にスペースが含まれる場合の処理では、-d '\n'
をオプションのリストに追加できます。
$ cat input.txt
A 1/B 1/C 1
A 2/B 2/C 2
A 3/B 2/C 2
$ cut -f1 -d '/' input.txt | xargs -d '\n' mkdir
$ ls
A 1 A 2 A 3 input.txt
@OleTangeがコメントで示唆しているA 12"x4" dir/B b/C c
など、より複雑なバリエーションの場合は、awk
を使用して、改行区切りリストではなくヌル区切りリストを作成できます。
awk -F'/' '{printf "%s\0",$1}' input.txt | xargs -0 mkdir
コメントの@dessertは、printf
の代わりにcut
を使用できるかどうか疑問に思っていました。技術的には、たとえば、印刷文字列を3文字の幅に制限することで使用できます。
xargs -d '\n' printf "%.3s\n" < input.txt | xargs -L1 mkdir
最もクリーンな方法ではありませんが、printf
を使用できることが証明されています。もちろん、ディレクトリ名が3文字より長くなると、これは問題になります。
perlを使用:
Perl -ne 'mkdir for /^(\w+)/' list.txt
または
Perl -ne 'mkdir for /^([^\/]+)/' list.txt
dir-namesでスペースを受け入れたい場合
GNU Parallelはこのタスクには過剰かもしれませんが、各行で他のことをしようとするなら、役に立つかもしれません:
cat myfile.txt | parallel --colsep / mkdir {1}
parallel -a myfile.txt --colsep / mkdir {1}
次のような入力を正しく処理します。
A 12"x4" dir/B b/C c