2

ベースのレベルを制御できることを除けば、 UNIXにたプログラムを作成しようとしています。basename

たとえば、プログラムは次のようなタスクを実行します。

$PROGRAM /PATH/TO/THE/FILE.txt 1
FILE.txt # returns the first level basename

$PROGRAM /PATH/TO/THE/FILE.txt 2
THE/FILE.txt #returns the second level basename

$ PROGRAM /PATH/TO/THE/FILE.txt 3
TO/THE/FILE.txt #returns the third level base name

私はこれを perl で書こうとしていましたが、自分の考えを手早くテストするために、次のコマンドライン スクリプトを使用して第 2 レベルのベース名を取得しましたが、役に立ちませんでした。

$echo "/PATH/TO/THE/FILE.txt" | perl -ne '$rev=reverse $_; $rev=~s:((.*?/){2}).*:$2:; print scalar reverse $rev'
/THE

ご覧のとおり、ディレクトリ名のみが出力され、残りは出力されません。これは、量指定子との貪欲でないマッチングと関係があると思いますが、その分野での私の知識は不足しています。

bashでこれを行うより効率的な方法がある場合は、アドバイスしてください

4

5 に答える 5

3

純粋なbashソリューション(引数の数などをチェックしない):

#!/bin/bash

IFS=/ read -a a <<< "$1"
IFS=/ scratch="${a[*]:${#a[@]}-$2}"
echo "$scratch"

終わり。

このように動作します:

$ ./program /PATH/TO/THE/FILE.txt 1
FILE.txt
$ ./program /PATH/TO/THE/FILE.txt 2
THE/FILE.txt
$ ./program /PATH/TO/THE/FILE.txt 3
TO/THE/FILE.txt
$ ./program /PATH/TO/THE/FILE.txt 4
PATH/TO/THE/FILE.txt
于 2012-11-13T20:03:34.993 に答える
3

$1の代わりにを使用すると、独自のソリューションがうまく機能することがわかります$2。キャプチャには、正規表現内で開き括弧が表示される順序で番号が付けられており、最も外側のキャプチャを保持する必要があります。ただし、コードはエレガントではありません。

このFile::Specモジュールは、この目的に最適です。これは Perl v5 のすべてのリリースでコア モジュールとなっているため、インストールする必要はありません。

use strict;
use warnings;

use File::Spec;

my @path = File::Spec->splitdir($ARGV[0]);
print File::Spec->catdir(splice @path, -$ARGV[1]), "\n";

出力

E:\Perl\source>bnamen.pl /PATH/TO/THE/FILE.txt 1
FILE.txt

E:\Perl\source>bnamen.pl /PATH/TO/THE/FILE.txt 2
THE\FILE.txt

E:\Perl\source>bnamen.pl /PATH/TO/THE/FILE.txt 3
TO\THE\FILE.txt
于 2012-11-13T19:27:35.250 に答える
1
#!/bin/bash                                                                                                                    

[ $# -ne 2 ] && exit

input=$1
rdepth=$2
delim=/

[ $rdepth -lt 1 ] && echo "depth must be greater than zero" && exit

parts=$(echo -n $input | sed "s,[^$delim],,g" | wc -m)
[ $parts -lt 1 ] && echo "invalid path" && exit

[ $rdepth -gt $parts ] && echo "input has only $parts part(s)" && exit

depth=$((parts-rdepth+2))

echo $input | cut -d "$delim" -f$depth-

使用法:

$ ./level.sh /tmp/foo/bar 2
foo/bar
于 2012-11-13T19:08:53.667 に答える
1

これを行うためのbashスクリプトは次のawkとおりです。

#!/bin/bash

level=$1
awk -v lvl=$level 'BEGIN{FS=OFS="/"}
    {count=NF-lvl+1;
    if (count < 1) {
        count=1;
    }
    while (count <= NF) {
        if (count > NF-lvl+1 ) {
            printf "%s", OFS;
        }
        printf "%s", $(count);
        count+=1;
    }
    printf "\n";
}'

これを使用するには、次のようにします。

$ ./script_name num_args input_file

たとえば、ファイルに「 」inputという行が含まれている場合/PATH/TO/THE/FILE.txt

$ ./get_lvl_name 2 < input
THE/FILE.txt
$
于 2012-11-13T19:09:04.353 に答える
1

@tripleee が言ったように、パス区切り文字 (Unix ライクの場合は「/」) で分割してから、一緒に貼り付けます。例えば:

echo "/PATH/TO/THE/FILE.txt" | perl -ne 'BEGIN{$n=shift} @p = split /\//; $start=($#p-$n+1<0?0:$#p-$n+1); print join("/",@p[$start..$#p])' 1
FILE.txt

echo "/PATH/TO/THE/FILE.txt" | perl -ne 'BEGIN{$n=shift} @p = split /\//; $start=($#p-$n+1<0?0:$#p-$n+1); print join("/",@p[$start..$#p])' 3
TO/THE/FILE.txt

楽しみのために、2 番目の引数として区切り文字を指定すると、Unix と Windows (およびその他のパス) の種類で機能するものを次に示します。

# Unix-like
echo "PATH/TO/THE/FILE.txt" | perl -ne 'BEGIN{$n=shift;$d=shift} @p = split /\Q$d\E/; $start=($#p-$n+1<0?0:$#p-$n+1); print join($d,@p[$start..$#p])' 3 /
TO/THE/FILE.txt
# Wrong delimiter
echo "PATH/TO/THE/FILE.txt" | perl -ne 'BEGIN{$n=shift;$d=shift} @p = split /\Q$d\E/; $start=($#p-$n+1<0?0:$#p-$n+1); print join($d,@p[$start..$#p])' 3 \\
PATH/TO/THE/FILE.txt
# Windows
echo "C:\Users\Name\Documents\document.doc" | perl -ne 'BEGIN{$n=shift;$d=shift} @p = split /\Q$d\E/; $start=($#p-$n+1<0?0:$#p-$n+1); print join($d,@p[$start..$#p])' 3 \\
Name\Documents\document.doc
# Wrong delimiter
echo "C:\Users\Name\Documents\document.doc" | perl -ne 'BEGIN{$n=shift;$d=shift} @p = split /\Q$d\E/; $start=($#p-$n+1<0?0:$#p-$n+1); print join($d,@p[$start..$#p])' 3 /
C:\Users\Name\Documents\document.doc
于 2012-11-13T19:11:00.330 に答える