2009-10-19 5 views
10

ho una cartella con i file che assomigliano a questo:BASH: Trova il nome del file il numero più alto in una directory in cui nomi iniziano con le cifre (ls, sed)

001_something.php 002_something_else.php 
004_xyz.php  005_do_good_to_others.php 

fine ho voglia di creare un nuovo, PHP vuoto file il cui nome inizia con il numero successivo della serie.

LIST=`exec ls $MY_DIR | sed 's/\([0-9]\+\).*/\1/g' | tr '\n' ' '` 

Il codice precedente mi dà una stringa come questa:

LIST='001 002 004 005 ' 

voglio afferrare che 005, incrementano di uno, e quindi utilizzare questo numero per generare il nuovo nome del file. Come posso farlo in BASH?

+0

È questo per l'esecuzione come parte di un'applicazione web? Se il web server accetta più richieste simultanee (la maggior parte lo fanno), come proteggi contro la condizione di competizione quando i processi A e B eseguono il controllo simultaneamente e poi creano un file con lo stesso numero? – telent

+0

no questo faceva parte di uno script di shell per emulare lo strumento di generazione di migrazione delle guide, per un'app di php che utilizza un'implementazione red-headed-stepchild del modello di migrazione del database. – Jake

risposta

10
$ LIST=($LIST) 
$ newfile=`printf %03d-whatever $((10#${LIST[${#LIST}]}+1))` 
$ echo $newfile 
006-whatever 

Quindi, questo è bash-specifico. Di seguito è una soluzione any-posix-shell-including-bash, quindi immagino che qualcosa di più semplice sia possibile.

$ cat /tmp/z 
f() { 
    eval echo \${$#} | sed -e 's/^0*//' 
} 
LIST='001 002 004 005 ' 
newname=`printf %03d-whatever $(($(f $LIST) + 1))` 
echo $newname 
$ sh /tmp/z 
006-whatever 
$ 
+0

non funziona con '008': –

+0

Questo perché i numeri che iniziano con "0" sono * ottale *. – paxdiablo

+0

Ok, risolto bug ottale. – DigitalRoss

0

Ecco una soluzione (è necessario bc):

#!/bin/bash 

LIST='001 002 008 005 004 002 ' 
a=0 

for f in $LIST 
do 
    t=$(echo $f + 1|bc) 
    if [ $t -ge $a ] 
    then 
     a=$t 
    fi 
done 

printf "%03d\n" $a 
+0

Puoi anche usare 'dc': t = $ (echo $ f 1 + pq | dc), o' expr': t = $ (expr $ f + 1), o bash math: t = $ (($ f + 1)) – mouviciel

1
$ for file in *php; do last=${file%%_*} ; done 
$ newfilename="test.php" 
$ printf "%03d_%s" $((last+1)) $newfilename 
006_test.php 

Lascio a voi fare la creazione di nuovo file

11

Avete bisogno tutto l'elenco?

Se non

LAST=`exec ls $MY_DIR | sed 's/\([0-9]\+\).*/\1/g' | sort -n | tail -1` 

vi darà solo la parte 005 e

printf "%03d" `expr 1 + $LAST` 

sarà stampare il numero successivo nella sequenza.

+0

alternativamente: printf "% 03d" $ ((1 + $ ULTIMO)) – leedm777

2

veloce, e senza loop (maniglie anche i nomi di file con spazi) * senza subshell:

list=([0-9]*) 
last=${list[@]: -1} 
nextnum=00$((10#${last%%[^0-9]*} + 1)) 
nextnum=${nextnum: -3} 
touch ${nextnum}_a_new_file.php 

Dato il vostro esempio i file di output sarà:

006_a_new_file.php 
7

Utilizzando solo strumenti standard, di seguito vi darà il prefisso per il nuovo file (006):

 
ls [0-9]* | sed 's/_/ _/' | sort -rn | awk '{printf "%03d", $1 + 1; exit}' 
+1

se il file 001 non esiste, non dovrebbe questo comando stampare 001? – Stefan

+0

Questo non funziona su directory contenenti molti, molti file - l'output è: bash:/bin/ls: lista argomenti troppo lunga –

+0

@John: basta sostituire 'ls [0-9] *' con 'ls | grep^[0-9] '. – Idelic

3

Questo sembra essere più semplice.

ls [0-9]* | sort -rn | awk '{FS="_"; printf "%03d_new_file.php\n",$1+1;exit}' 
1
  1.  
    touch "newfile_$(printf "%03d" $(echo $(ls 00?_*.php|sed 's/_.*//'|sort -rn|head -1)+1|bc))" 
    

    2.

    num=$(ls 00?*.php|sed 's/.*//'|sort -rn|head -1) 
    touch $(printf "newfile_%03d" $((num+1)))