GNU/Linux >> Belajar Linux >  >> Linux

Buat file baru tetapi tambahkan nomor jika nama file sudah ada di bash

Untuk menghindari kondisi balapan :

name=some-file

n=
set -o noclobber
until
  file=$name${n:+-$n}.ext
  { command exec 3> "$file"; } 2> /dev/null
do
  ((n++))
done
printf 'File is "%s"\n' "$file"
echo some text in it >&3

Dan sebagai tambahan, Anda memiliki file yang terbuka untuk ditulis di fd 3.

Dengan bash-4.4+ , Anda dapat membuatnya menjadi fungsi seperti:

create() { # fd base [suffix [max]]]
  local fd="$1" base="$2" suffix="${3-}" max="${4-}"
  local n= file
  local - # ash-style local scoping of options in 4.4+
  set -o noclobber
  REPLY=
  until
    file=$base${n:+-$n}$suffix
    eval 'command exec '"$fd"'> "$file"' 2> /dev/null
  do
    ((n++))
    ((max > 0 && n > max)) && return 1
  done
  REPLY=$file
}

Untuk digunakan misalnya sebagai:

create 3 somefile .ext || exit
printf 'File: "%s"\n' "$REPLY"
echo something >&3
exec 3>&- # close the file

max value dapat digunakan untuk mencegah loop tak terbatas ketika file tidak dapat dibuat karena alasan lain selain noclobber .

Perhatikan bahwa noclobber hanya berlaku untuk > operator, bukan >> maupun <> .

Kondisi balapan yang tersisa

Sebenarnya, noclobber tidak menghapus kondisi balapan dalam semua kasus. Ini hanya mencegah pukulan biasa file (bukan jenis file lain, sehingga cmd > /dev/null misalnya tidak gagal) dan memiliki kondisi balapan sendiri di sebagian besar shell.

Shell pertama-tama melakukan stat(2) pada file untuk memeriksa apakah itu file biasa atau tidak (fifo, direktori, perangkat...). Hanya jika file tersebut tidak ada (belum) atau merupakan file biasa yang melakukan 3> "$file" gunakan flag O_EXCL untuk menjamin tidak merusak file.

Jadi jika ada file fifo atau perangkat dengan nama itu, itu akan digunakan (asalkan dapat dibuka hanya untuk menulis), dan file biasa dapat dihancurkan jika dibuat sebagai pengganti fifo/perangkat/direktori. .. di antara stat(2) itu dan open(2) tanpa O_EXCL!

Mengubah

  { command exec 3> "$file"; } 2> /dev/null

untuk

  [ ! -e "$file" ] && { command exec 3> "$file"; } 2> /dev/null

Akan menghindari penggunaan file non-reguler yang sudah ada, tetapi tidak mengatasi kondisi balapan.

Sekarang, itu hanya masalah di hadapan musuh jahat yang ingin membuat Anda menimpa file arbitrer pada sistem file. Itu menghapus kondisi balapan dalam kasus normal dari dua contoh skrip yang sama berjalan pada waktu yang sama. Jadi, lebih baik daripada pendekatan yang hanya memeriksa keberadaan file sebelumnya dengan [ -e "$file" ] .

Untuk versi yang berfungsi tanpa kondisi balapan sama sekali, Anda dapat menggunakan zsh shell bukannya bash yang memiliki antarmuka mentah ke open() sebagai sysopen bawaan di zsh/system modul:

zmodload zsh/system

name=some-file

n=
until
  file=$name${n:+-$n}.ext
  sysopen -w -o excl -u 3 -- "$file" 2> /dev/null
do
  ((n++))
done
printf 'File is "%s"\n' "$file"
echo some text in it >&3

Lebih mudah:

touch file`ls file* | wc -l`.ext

Anda akan mendapatkan:

$ ls file*
file0.ext  file1.ext  file2.ext  file3.ext  file4.ext  file5.ext  file6.ext

Skrip berikut dapat membantu Anda. Anda tidak boleh menjalankan beberapa salinan skrip secara bersamaan untuk menghindari kondisi balapan.

name=somefile
if [[ -e $name.ext || -L $name.ext ]] ; then
    i=0
    while [[ -e $name-$i.ext || -L $name-$i.ext ]] ; do
        let i++
    done
    name=$name-$i
fi
touch -- "$name".ext

Linux
  1. File Baru Hilang Di Ubuntu 13.04?

  2. Di Bash, bagaimana cara menambahkan string setelah setiap baris dalam file?

  3. tambahkan baris ke file HANYA jika belum ada dalam file

  1. Menambahkan stempel waktu ke nama file dengan mv di BASH

  2. Cara memasukkan file dalam skrip bash shell

  3. Bagaimana cara menambahkan ikon ke prompt bash

  1. atom buat file jika tidak ada dari skrip bash

  2. Cara hanya mendapatkan jumlah baris file

  3. Jenkins mati tetapi file pid ada