grep Dateianfang?


10

In einer Linux-Shell möchte ich sicherstellen, dass alle bestimmten Dateien mit <?genau dieser Zeichenfolge und keinen anderen Zeichen am Anfang beginnen. Wie kann ich grep oder eine andere verwenden, um "Datei beginnt mit" auszudrücken?


Bearbeiten: Ich verzeichne dies mit einem Platzhalter und headgebe keinen Dateinamen in derselben Zeile an. Wenn ich ihn greife, wird der Dateiname nicht angezeigt. Scheint "^<?"auch nicht die richtigen Ergebnisse zu liefern; Im Grunde bekomme ich das:

$> head -1 * | grep "^<?"
<?
<?
<?
<?
<?
...

Alle Dateien sind tatsächlich gut.

Antworten:


11

In Bash:

for file in *; do [[ "$(head -1 "$file")" =~ ^\<\? ]] || echo "$file"; done

Stellen Sie sicher, dass es sich um Dateien handelt:

for file in *; do [ -f "$file" ] || continue; [[ "$(head -1 "$file")" =~ ^\<\? ]] || echo "$file"; done


und da wir alle so pedantisch sind: Verwenden Sie den Glob-Operator nicht für große Mengen von Dateinamen, sondern verwenden Siefind
akira

using findkann auch nur einfache Dateien direkt zurückgeben, um die Pipe zu starten.
mpez0

1
Sie können es vollständig in Bash tun, wenn Sie readstattdessen headauch verwenden: for file in *; do [ -f "$file" ] || continue; read < "$file"; [[ "$REPLY" =~ ^\<\? ]] || echo "$file"; done
janmoesen

4

Mach das grep:

$ head -n 1 * | grep -B1 "^<?"
==> foo <==
<?
--
==> bar <==
<?
--
==> baz <==
<?

Analysieren Sie die Dateinamen:

$ head -n 1 * | grep -B1 "^<?" | sed -n 's/^==> \(.*\) <==$/\1/p'
foo
bar
baz

3

Sie können awk dafür verwenden:

$ cat test1
<?xxx>
111
222
333
$ cat test2
qqq
aaa
zzz
$ awk '/^<\?/{print "Starting with \"<?\":\t" ARGV[ARGIND]; nextfile} {print "Not starting with \"<?\":\t" ARGV[ARGIND]; nextfile}' *
Starting with "<?":     test1
Not starting with "<?": test2
$

3

Mit Ausnahme leerer Dateien scheint dieses Perl-Skript zu funktionieren:

perl -e 'while (<>) { print "$ARGV\n" unless m/^<\?/; close ARGV; }' *

Ich bin mir nicht sofort sicher, wie ich mit leeren Dateien umgehen soll. Ich wäre versucht, sie als separaten Sonderfall zu behandeln:

find . -type f -size +0 -print0 |
    xargs -0 perl -e 'while (<>) { print "$ARGV\n" unless m/^<\?/; close ARGV; }'

2

Versuche dies

for i in `find * | grep "php$"`; do echo -n $i " -> "; head -1 $i; done

Dadurch wird eine Liste aller Dateien angezeigt, die auf PHP enden, und anschließend durchlaufen. Echo des Dateinamens und dann Drucken der ersten Zeile der Datei. Ich habe gerade eingefügt

gibt Ihnen Ausgabe wie:

calendar.php  -> <?php
error.php  -> <?php
events.php  -> <?php
gallery.php  ->
index.php  -> <?php
splash.php  -> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
information.php  -> <?php
location.php  -> <?php
menu.php  -> <?php
res.php  -> <?php
blah.php  -> <?php

Dann können Sie am Ende einen normalen Grep verwenden, um das, was Sie sehen möchten, loszuwerden und nur Ausnahmen zu finden

for i in `find * | grep "php$"`; do echo -n $i " -> "; head -1 $i; done | grep -v "<?php"

Ausgabe:

gallery.php  ->
splash.php  -> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

4
Nutzlose Verwendung von grep; benutze "find -name '* .php'". Gefährliche Verwendung von Variablen: Verwenden Sie "find -exec your command here '{}' '+'", um Probleme mit "speziellen" Dateinamen zu vermeiden. Abgesehen davon zitieren Sie immer Ihre Variablen: "head -1" $ i "", nicht "head -1 $ i".
Janmoesen

for x in *.php;do echo $x \"head -n1 $ x\";done
user23307

1

Bash 4.0

#!/bin/bash
shopt -s globstar
for php file in /path/**/*.php
do
   exec 4<"$php";read line <&4;exec 4<&-
   case "$line" in
     "<?"*) echo "found: $php"
   esac

done

0
cat file.txt | head -1 | grep "^<?"

sollte tun, was Sie verlangen.


Ja, aber wenn ich einen Platzhalter habe, gibt es mir keine Dateinamen :( Auch "^ <?"
Hat

2
@Phoshi Zwanghafte catNutzung head -1 file.txt | grep "^<?"ist genug.
Benjamin Bannier

1
Nutzloser Gebrauch von Katze: - (((
vwegert

Nutzlose Katze ist nutzlos :(
user13743

Ich finde es viel einfacher, sich Befehle zu merken, wenn man alles modular und aufgeschlüsselt hält. Ich weiß, dass Cat funktionieren wird, ich weiß nicht, ob commandich die Datei als Argument nehmen werde. Es ist vielleicht nicht unbedingt notwendig, aber ich nehme es nicht raus :)
Phoshi

0

diese:

  % for i in *; do head -1 $i | grep "^<?" ; echo "$i : $?"; done

gibt Ihnen so etwas:

  foo.xml: 0
  bla.txt: 1

Jede Datei, die Ihr Muster nicht enthält, wird mit "1" "markiert". Sie können damit spielen, bis es Ihren Bedürfnissen entspricht.


1
Sie müssen die Dateinamen angeben, wenn sie Leerzeichen enthalten können. Und Sie möchten wahrscheinlich die Ausgabe von 'grep' an / dev / null verlieren. Sie können auch Folgendes verwenden: head -1 "$i" | grep '^<?' || echo "$i"Der Dateiname wird nur gedruckt, wenn dies problematisch ist.
Jonathan Leffler

2
Dafür ist "grep -q" da. :-)
Janmoesen

0

Lassen Sie mich das ausprobieren

find -type f | awk '
{
 if (getline ret <$ 0) {
  if (ret ~ "^ <\\? $") {
   print "Good [" $ 0 "] [" ret "]";
  }sonst{
   print "Fail [" $ 0 "]";
  };
 }sonst{
  print "leer [" $ 0 "]";
 };
 schließen ($ 0);
} '

niemand sagte, wak sei nicht verfügbar :-)

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.