web-dev-qa-db-ja.com

sedを使用してファイル名のみを取得する方法

Sedを使用してファイル名のみを取得するにはどうすればよいですか?私はこれを持っています

out_file=$(echo $in_file|sed "s/\(.*\.\).*/\1mp4/g")

しかし、パスも取得します/root/video.mp4、そして私はvideo.mp4

18
Shixons

GNU coreutils からのbasenameは、この仕事を助けることができます:

$ basename /root/video.mp4
video.mp4

ファイルの拡張子がわかっている場合は、構文basename NAME [SUFFIX]を使用してbasenameを呼び出し、ファイルを削除できます。

$ basename /root/video.mp4 .mp4
video

または、sedを使用して、最後のドット以降をすべてカットすることもできます。

$ basename /root/video.old.mp4 | sed 's/\.[^.]*$//'
video.old
28
uloBasEI

最も簡単な解決策は、/が最後に現れるまですべてを削除することです。

echo /root/video.mp4 | sed 's/.*\///'

9
daisy

次のいずれかの方法を使用します。

_out_file="${in_file##*/}"

out_file="$(basename $in_file)"

out_file="$(echo $in_file | sed 's=.*/==')"

out_file="$(echo $in_file | awk -F"/" '{ print $NF }')"
_

ps。ステートメントでは\(.*\.\)が最初からドットまでの文字列(_/root/video._)に一致するため、同じ文字列が得られます。次に、元の文字列と同じ_.mp4_を手動で追加しますストリング。代わりにs=.*\([^/]*\)=\1=を使用してください。

更新:(最初の1つは現在修正されています)

拡張子なしの唯一のファイル名を取得するには、次のようにします。

_out_file="$(echo $in_file | sed 's=.*/==;s/\.[^.]*$/.new_ext/')"

out_file="$(echo $in_file | sed 's=\([^/]*\)\.[^./]*$=\1.new_ext=')"

out_file="$(echo $in_file | awk -F"/" '{ gsub (/\.[^/.]*$/,".new_ext",$NF);print $NF }'
_
5
rush

正規表現を使用する際の基本の1つは、ワイルドカードを指定する場合、パターンは本質的に貪欲であることです。 @uloBasEIによって提案された回答は確かに有効な回答ですが、basenameコマンドを使用する必要もあります。 @Shixonsからの元の質問は、sedのみを使用するソリューションを要求します。

続行する前に、sedのどのバージョンがターゲットであるかを知ることは常に役に立ちます。私は(OSXに同梱されている)BSDを想定しています。

まず、元の質問で提案されたパターンは、入力文字列の先頭から最後のドットまでのすべてをキャプチャするため、機能しません。アンカーがないと、この検索はすべてを左から右に飲み込みます。したがって、「/ 1」の一致したパターンは、最後のドットまでのすべてです。複数のドットがあるファイル名であっても、全体が飲み込まれてしまいます。まったく望ましい結果ではありません。

最初のステップは、パターンを識別するための戦略を確立することです。ここでは、ファイル名の左側にあるすべてのものを削除します(後で拡張子を扱います)。

out_file="$(echo $in_file | sed 's/^\(\/.*\/\)*.*/\1/')"

検索は文字列の先頭から一致します。 「/.*」のパターンに0回以上一致し、その後すべてを削除します。一致したパターンを「\ 1」で印刷します。私たちはグローバルに検索していません。 ^アンカーを指定して、文字列の先頭から検索します。

括弧をエスケープする必要がないように「-E」オプションを有効にすることで、より明確になりました。

out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*.*/\1/')"

これで左側のパーツができました。右側のパーツを追加してみましょう。左部分をパターンとして保持する必要があることに注意してください。これは、0回以上出現するように指定できるためです。ここでは、右側のパーツのパターンを追加するだけです。

out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)/\2/')"

2番目の一致のみを出力するため、ファイル名以外はすべて破棄されます。ただし、ファイル名拡張子を削除する必要があります。

out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)\..*$/\2/')"

末尾の「$」はオプションです。

最後に、新しい拡張機能を追加するには、次のように修正するだけです。

out_file="$(echo $in_file | sed -E 's/^(\/.*\/)*(.*)\..*$/\2.mp4/')"

追加の最適化は、相対パスを処理するために最初のスラッシュをオプションにすることです:

out_file="$(echo $in_file | sed -E 's/^([\/]?.*\/)*(.*)\..*$/\2.mp4/')"

basenameを置き換えるsedパターンを探している間に怠惰になってこの質問に出くわしました。そのコマンドがインストールされていないストリップシステムで作業しています。

4
markeissler