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.

user13743
quelle

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

janmoesen
quelle
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
Bis auf weiteres angehalten.
quelle
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
$
hlovdal
quelle
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; }'
Jonathan Leffler
quelle
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">
Roy Rico
quelle
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
user31894
quelle
0
cat file.txt | head -1 | grep "^<?"

sollte tun, was Sie verlangen.

Phoshi
quelle
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.

Akira
quelle
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 :-)

user42723
quelle