'ls -1':拡張子なしでファイル名をリストする方法


24

ls -1 私の要素を次のようにリストします:

foo.png
bar.png
foobar.png
...

私はそれなしでリストにしたい.pngので:

foo
bar
foobar
...

(ディレクトリには.pngファイルのみが含まれます)

grepこの場合の使用方法を教えてもらえますか?

目的:すべての名前が拡張子なしでリストされているテキストファイルがあります。テキストファイルとフォルダーを比較して、不足しているファイルを確認するスクリプトを作成します。


36
このようなリクエストには注意が必要です。Linuxにはファイル名拡張子がありません。Linuxには、ファイル名にa .が含まれている場合と含まれていない場合があります。慣例.pngでは最後にファイルに名前を付けるようになっていますが、foo.zipor my.picture.20160518またはor という名前のPNGファイルを作成できない理由はありませんmypic
ハイミー

2
@hymie私は知っていますが、そのフォルダ内の私の要素はすべて最後に.pngという名前が付けられています。
コリン

14
「拡張」とは何ですか?これはUnixファイルの命名の一部ではありません。VMS / NT / Windowsからのキャリーオーバーです。そして、あなたの若者も私の芝生を降ります。:)
mpez0

28
これを誇張しないでください。OSは拡張子を単にファイル名の一部として扱いますが、多くのUNIXプログラムはコンパイラからGUIまで、それらに注意を払っています。この概念は、Unixにとって異質ではありません。
アレクシス

1
通常に提案されたの出力解析するために避けるlsの出力とパイプへのlsおよびfind可能性がで負担する主な理由は、newlineファイル名にタブ文字`、。ファイル名がThe new art of working on .png\NEWLINE files and other formats多い場合、提案された解決策が問題を引き起こします。
ハスター

回答:


41

このジョブに必要なのはシェルのみです。

POSIXly:

for f in *.png; do
    printf '%s\n' "${f%.png}"
done

zsh

print -rl -- *.png(:r)

4
の必要はありませんprintfecho ${f%.png}十分であろう。
デビッドコンラッド

11
@Conrad:ファイル名がダッシュで始まるか、エスケープされたシーケンスが含まれている場合、エコーの使用が適切に機能しない場合があります。
クオンルム

3
@DavidConradも参照してくださいunix.stackexchange.com/a/65819/38906
cuonglm

35
ls -1 | sed -e 's/\.png$//'

sedコマンドを除去(つまり、それは空の文字列に置き換えます)任意の文字列.pngで見つかった最後のファイル名の。

.以下のようにエスケープされ\.、それをすることによって解釈されるように、sedリテラルとして.文字ではなく、正規表現.(手段は、任意の文字に一致します)。$それが一致していないので、行末アンカーで.png、ファイル名の真ん中に。


4
OPは拡張機能を削除することを望んでいますが、おそらく「最後の拡張機能」のみを削除する必要があります。そのため、おそらくあなたとそうでない場合は良い答えを変更しますsed 's/\.[^.]*$//'
Otheus

1
はい、その正規表現は、その場合には動作します...しかし、OPはそれを望んでいるならば、彼らは代わりに、特に彼らは「それは.PNGせずにリストされたい」というのがそう言うべき
CAS

4
これ-1は必須ではなく、ここではデフォルトです。
jlliagre

3
@jlliagre cas -1に指定する必要があることに同意します。パイプがオンになっているときのみデフォルトであり、一部の人にとっては隠された驚きです。したがって、明示的にすると理解しやすくなります。また、スクリプトでこれを行うため、どのような出力が期待されているかがわかります。
オテウス

1
警告.png改行文字の前に キー()が付いたファイル名の場合.png、最後の文字だけでなく、それも消去します。lsの出力をパイプして解析するのを避ける方が良いです。しばしばよく隠された驚きを保留します...
ハスター

16

bashを使用するだけの場合:

for i in *; do echo "${i%.png}"; done

grep一致するものを見つけようとするときsedは、適切な削除/置換を行うのではなく、到達する必要があります。

find . -maxdepth 1 -name "*.png"  | sed 's/\.png$//'

PNGファイルに順序を付けるためにいくつかのサブディレクトリを作成する必要があると判断したら、それを次のように簡単に変更できます。

find . -name "*.png"  | sed 's/\.png$//'

ls -1 | sed 's / .png //'はうまく機能します。ありがとうございました!
コリン

名前の一部として、改行文字の直前にキー()を含むファイルを見つけた場合、ソリューションへのfind パイプsedいくつかの問題を引き起こす可能性が.pngあります。findまたはの出力をパイプして解析することを避ける方が良いlsです。多くの場合、よく隠された驚きを保存します...
ハスター

おそらく最後の例のfindようなものに置き換えてくださいechofindそこにどんな目的があり、結果はディレクトリ構造に依存します(つまり、ディレクトリがある場合files.png

@BroSlowより賢明なものに更新されました。
アントン

13

私はbasename(GNU実装を仮定して)行きたい:

basename --suffix=.png -- *.png

パイプで使用したい場合は、GNU basename -z(または--zero)オプションを使用して、(改行で区切られた)NULで区切られた出力を生成すると便利です。
トビースパイト

11

別の非常によく似た答え(この特定のバリアントがまだ登場していないことに驚いています):

ls | sed -n 's/\.png$//p'
  • 標準出力がターミナル(この場合はパイプ)でない場合は、と仮定-1するためls、のオプションは必要ありませんls
  • 「デフォルトで行を印刷しない」こと-nsed意味するオプション
  • /p置換の最後のオプションは、「...置換が行われた場合にこの行を出力する」ことを意味します。

その最終的な効果は、で終わる行のみを印刷し.pngて、.png削除することです。つまり、これはOPの質問のわずかな一般化にも対応しています。この場合、ディレクトリには.pngファイルのみが含まれません。

このsed -n手法は、通常grep + sedを使用する場合に役立ちます。


私はあなたがあなたの答えを書くのにどのように注意を払ったかが好きです。この解決策は、改行を含むファイル名に関する問題を提示し、名前の最初の部分を印刷しません。さらに.png、改行文字の前にキー()が付いた厄介なものである場合:その場合、pngなしでその部分を印刷し、最後の部分のみを消去しません。ls問題があなたが考えていないところに隠される可能性があるため、出力の解析(およびパイプ)を避けるために、しばしば推奨されます...-
Hastur

2
@Hasturあなたは原則として正しいです。そして、lsを解析しないことに関する有名なページには、病理学的ファイル名を渡すときのさらなる問題(および解決策)がリストされています。しかし、それを処理する最善の方法は、病的なファイル名(doh!)を避けることです。できない場合、またはそれらに対して堅牢でなければならない場合は、それらを管理するfindよりも強力な言語を使用するか、おそらくより良い方法を使用しshます(すべてsh 実行できるということは、それが最良の選択であることを意味しません各ケース)。シェルは最初に使いやすさを考慮して設計されています。
ノーマングレイ

原則として、使いやすさについては同意しますが、各改行が内部にあるファイル名がある場合、このバリアントは失敗します。これは、たとえば、GUIでPDFから行をコピーして貼り付ける場合に、気付かれずに簡単に発生する可能性があります
ハスター

さらに、私見解析を開始するのは簡単lsですが、将来の問題が発生しています。多くの場合、後で制限を忘れるときに使用するスクリプトを作成します...(それは人間です、通常です)。私find-exec純粋なシェルのために)cuonglmの、固体でposixに準拠したものにもっと良いと思う場合でも、(パイプの有無にかかわらず)例を提案しました。
ハスター

@Hastur:これらの将来の問題はとにかく発生します。システム内の多くのものは、改行を含むファイルに対して堅牢ではありません。例えば、使用してみてくださいlocateまたはmakeそれらに。
reinierpost

8

これを行うには、BASHコマンドのみを使用できます(外部ツールなし)。

for file in *; do echo "${file%.*}"; done 

これは、/ usr / binがない場合に便利であり、this.is.image.pngのようなファイル名とすべての拡張子でうまく機能します。


6

解析することは安全でないls又はパイプにfind[ 12 ]

解析しても安全(パイプに)の出力ではないlsか、findそれが可能に見つけることが主な理由は、ファイル名などの非通常の文字、改行タブ ...ここでは、純粋なシェルサイクルがうまくいく[ cuonglm ]。オプションでパイプされていないコマンドで
も動作します:find-exec

find ./*.png  -exec  basename {} .png  \;

更新/メモfind .隠しファイルを検索したり、隠されfind ./*.pngていないファイルのみを取得したりできます。ではfind *.png -exec ...あなたは場合の問題点を持つことができ、それは名前のファイルに存在していた.pngのfindはオプションとしてそれを取得しますので。あなたは追加することができます-maxdepth 0という名前のディレクトリに下降しないようにするにはDir_01.png、またはfind ./*.png -prune -exec ...MAXDEPTHは(感謝ステファン)許可されていないとき。これらのディレクトリを一覧表示したくない場合は、オプションを追加する必要があります-type f(他の種類の非正規ファイルも除外されます)。man使用可能なすべてのオプションについてのより完全なパノラマを見てください。移植性を高めるために、それらがPOSIX準拠であるかどうかを必ず確認してください。

もっと言葉を

たとえば、ドキュメントからタイトルをコピーしてファイル名に貼り付けると、1つ以上の改行がファイル名自体で終了することがあります。さらに、改行の直前に使用しなければならないキーさえもタイトルに含めることができるほど不運な場合もあります。

The new art of working on .png
files and other formats.

テストする場合は、コマンドを使用してこのようなファイル名を作成できます

touch "A file with two lines"$'\n'"and This is the second.png"
touch "The new art of working on .png"$'\n'"files and other formats.png"

印刷不可能な文字の代わりにシンプル/bin/ls *pngが出力されます?

A file with two lines?and This is the second.png
The new art of working on .png?files and other formats.png

出力パイプするすべての場合、lsまたはfind次のコマンドには、現在の行が新しいファイル名に由来するのか、それとも前のファイル名の改行文字に続くのかを理解するヒントがありません。厄介な実際の名前、まだ法的1。

シェルパラメータ膨張有するシェルサイクルは${parameter%word}、変異体との両方にprintf、またはecho動作します[ cuonglm ]、[ Anthon1 ]

for f in *.png; do printf "%s\n" "${f%.png}" ; done

Shell Parameter Expansion [ 3 ]のmanページから

$ {parameter%word}
$ {parameter %% word}

...展開の結果は、最短一致パターン(「%」ケース)または最長一致パターン(「%%」ケース)が削除されたパラメーターの値です。


また、findコマンドの結果はビット変数です(たとえば、というディレクトリがある場合files.png

1
親愛なる@BroSlow、上記の答えを書いたとき 、シェル呼び出しの引数として起動されたスクリプトで、その瞬間に存在する他のバリアント(全部で13)を試しました。同じことを行い、期待どおりに動作するかどうかを教えてください。テストはbash 4.3.11、ダッシュ0.5.7-4、zsh(必要な場合)5.0.2で行いました。何かを追加するこの投稿を自由に読んでください。の出力をパイピングすることに注意してください。findこれについては、明示的に提案-execし、タイトルに書きました。:-)
ハスター

wikiを再度読み直してください。私はまだあなたの例でパイプする必要があると思います、それがここで議論されているものだからです。また、最新バージョンの大部分でlsは、出力がパイプ処理またはリダイレクトされても何の問題もありませんが、wikiで述べられているように、すべてで機能するわけではありません。ほとんどの?場合、出力が端末に送信されるときに特殊文字の代わりに挿入されるだけです。つまり、Do echo *.png | od -cls *.png | od -c。改行の問題は、の問題ではなくls、パイプの両側でヌル終了しないコマンドの問題です。

1
printf "${f%.png}\n"間違っている。最初の引数は形式です。そこで変数データを使用しないでください。DoSの脆弱性と見なすこともできます(%1000000000s.pngたとえば、ファイルで試してみてください)。
ステファンシャゼラス

あなたは、必要があると思いますfind ./*.png -prune -exec...か、ファイル名に問題で始まる必要があるだろう-(と型ディレクトリのファイル、ノート-maxdepthポータブルではありません)
ステファンChazelas

4

十分じゃなかった?

ls -1 | sed 's/\.png//g'

または一般的に、これ

ls -1 | sed 's/\.[a-z]*//g'

すべての拡張機能を削除します


しかし、他のソリューションも機能します。
コリン

あなたの質問はls -1で始まったので、ls -1でそれを行う必要があります。:)
ロハイルアッバス

これ-1は必須ではなく、ここではデフォルトです。
jlliagre

@Rohail Abbasしかし、すべてのシステムがインストールされているわけではありませんか?
コリン

1
確かに、しかしls、出力が端末ではない場合は、このオプションなしで実行します。
-jlliagre

3

使用rev

ls -1 | rev | cut -f 2- -d "." | rev

revすべての文字列(行)を反転します。最初の「。」の後にすべてをカットします revはレムナントを元に戻します。

grep「アルマ」にしたい場合:

ls -1 | rev | cut -f 2- -d "." | rev | grep 'alma'

これ-1は必須ではなく、ここではデフォルトです。
jlliagre

2
これは名前のファイルでひどく失敗しますMy.2016.Summer.Vacation.png
デビッドコンラッド

@DavidConrad私の悪い:/に修正しましたcut -f 2-
トムソリッド

今ではそのファイルで動作しますが、まだ.png直後に改行がありません... ls驚きを隠すのが好きなので、解析を避けることをお勧めします... :
Hastur

2

ディレクトリに拡張子が.pngのファイルしかないことがわかっている場合、次のコマンドを実行するだけです。 ls | awk -F. '{print $1}'

これは、filename.extensionが存在するすべての項目の最初の「フィールド」を返します。

例:

[rsingh@rule51 TESTDIR]$ ls
10.png  1.png  2.png  3.png  4.png  5.png  6.png  7.png  8.png  9.png

[rsingh@rule51 TESTDIR]$ ls | awk -F. '{print $1}'
10
1
2
3
4
5
6
7
8
9

残念ながら、それはすべてに失敗するファイル名を複数で.、などImage.1.pngとさえを持つものではない素敵な名前内部の特殊文字を使用し、。改行またはあなたが(入力)レコードセパレータとして使用することを1としてawkRS。予期しlsないときに発生する問題を隠すのが大好きなので、出力の解析を避けることをお勧めします。これらの参考文献1または2で詳細を読むことができます。ところで、awkを使用するというアイデアは素晴らしいです... 1つの答えにいくつかの例を示しました。
ハスター

確かに、Colinから提供されたサンプルを考えると、問題なく動作します。提案されたケースで機能するように、おそらく次のように変更します:[rsingh @ rule51 TESTDIR] $ ls | sed -e 's / .png $ //' 10 1 2 3 4 5 6 7 8 9 harry.the.bunny whats.a.png.filename難しくしようとはしないが、コリンの必要性を考えると、よくわからないlsの解析で問題になるもの。
rsingh

すみません... lsの出力を変更する前に、sedの前にファイルのあるディレクトリを表示しなかったことに気付きました[rsingh @ rule51 TESTDIR] $ ls 10.png 2.png 4.png 6.png 8.png harry.the.bunny.png 1.png 3.png 5.png 7.png 9.png whats.a.png.filename.png [rsingh @ rule51 TESTDIR] $ ls | sed -e 's / .png $ //' 10 1 2 3 4 5 6 7 8 9 harry.the.bunny whats.a.png.filename
rsingh

注1.でin をエスケープする必要がありますが、それはちょうど書かれた答えになります。:-( 注2 ...のようなもので使用することができますが、行がファイル名内の改行であるかどうかをawkが知ることができないという問題が常に発生します。 。\.sed -e 's/\.png$//'awkls | awk -F. '{if ($NF=="png") {for (i=1;i<NF-1;i++) printf("%s.", $i) ; printf $(NF-1)"\n"}}'
ハスター

おかげで、私はそれを見逃した:)。また、このケースではsedを優先してawkの使用をやめました。
rsingh

2

あなたのコメントによると、「拡張子なしですべての名前がリストされているテキストファイルがあります。テキストファイルとフォルダを比較して、不足しているファイルを確認するPHPスクリプトを作成したいです」

for file in $(cat yourlist) ; do
  [ -f "${file}.png" ] || {
    echo "$file : listed in yourlist, but missing in the directory"
  }
done
#assumes that filenames have no space...
# otherwise use instead:
#  while IFS= read file ; do ...(same inner loop as above)... ; done < yourlist

そしてその逆:

for file in *.png ; do
  grep "^${file%.png}$" yourlist >/dev/null || {
    echo "$file: present in the directory but not listed in yourlist"
  }
done
#I assume there are no spaces/tabs/? before/after names in 'yourlist'. Change the script accordingly if there are some (or sanitize the list)

1

ls -l | sed 's/\.png$//'

@roaimaで強調されているように、最も正確な方法です。エスケープされた\.pngファイルがなければ、名前a_png.pngは次のようにリストされますa_


を使用するls -lと、ファイルの詳細が表示されますが、これはOPが尋ねたものではありません。
アントン

1

単純なシェル行(ksh、bashまたはzsh。ダッシュではありません):

set -- *.png; printf '%s\n' "${@%.png}"

単純な関数(拡張子なし):

ne(){ set -- *.png; printf '%s\n' "${@%.png}"; }

または、指定された拡張子(デフォルトではpng)を削除する関数:

ne(){ ext=${1:-png}; set -- *."$ext"; printf '%s\n' "${@%.${ext}}"; }

使用:

ne jpg

出力がアスタリスクの場合、*その拡張子を持つファイルは存在しません。


1

次のフィードを試すことができます。あなたのスーペレータの出力が「。」の場合 そして、すべてのファイルにはname.pngがあるため、最初の列を印刷します。
ls | awk -F"." '{print $1}'


-1

sedにアクセスした場合、最後のファイル拡張子が何であるかに関係なく(png、jpg、tiffなど)削除されるため、これはより優れています

ls | sed -e 's/\..*$//'

7
のようなファイル名の区切りthis.is.a.dotty.txts/\.[^.]*$//代わりに試してください。
ロアイマ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.