#! / bin / sh vs #! / bin / bash για μέγιστη φορητότητα

cherouvim 07/30/2017. 3 answers, 2.886 views
linux bash shell sh

Συνήθως δουλεύω με τους διακομιστές Ubuntu LTS οι οποίοι από αυτό που καταλαβαίνω symlink /bin/sh σε /bin/dash . Πολλά άλλα distros αν και symlink /bin/sh σε /bin/bash .

Από αυτό κατανοώ ότι αν ένα σενάριο χρησιμοποιεί #!/bin/sh στην κορυφή μπορεί να μην τρέχει με τον ίδιο τρόπο σε όλους τους διακομιστές;

Υπάρχει μια προτεινόμενη πρακτική για το οποίο το κέλυφος να χρησιμοποιήσει για δέσμες ενεργειών όταν κάποιος θέλει μέγιστη φορητότητα αυτών των σεναρίων μεταξύ των διακομιστών;

1 Comments
Thorbjørn Ravn Andersen 08/01/2017
Υπάρχουν μικρές διαφορές μεταξύ των διαφόρων κοχυλιών. Εάν η φορητότητα είναι η πιο σημαντική για εσάς στη συνέχεια χρησιμοποιήστε #!/bin/sh και μην χρησιμοποιείτε τίποτα άλλο από αυτό που παρέσχε το αρχικό κέλυφος.

3 Answers


Gordon Davisson 08/01/2017.

Υπάρχουν περίπου τέσσερα επίπεδα φορητότητας για δέσμες ενεργειών κελύφους (όσον αφορά τη γραμμή shebang):

  1. Το πιο φορητό: χρησιμοποιήστε ένα #!/bin/sh shebang και χρησιμοποιήστε only τη βασική σύνταξη κελύφους που καθορίζεται στο πρότυπο POSIX . Αυτό θα πρέπει να λειτουργεί σε οποιοδήποτε σύστημα POSIX / unix / linux. (Λοιπόν, εκτός από το Solaris 10 και το νωρίτερο που είχε το πραγματικό κέλυφος Bourne κληρονομιάς, πριν από το POSIX να μην είναι συμβατό, όπως /bin/sh .)

  2. Δεύτερα πιο φορητό: χρησιμοποιήστε γραμμή #!/bin/bash#!/usr/bin/env bash ) shebang γραμμή, και ραβδί για bash v3 χαρακτηριστικά. Αυτό θα λειτουργήσει σε οποιοδήποτε σύστημα που έχει bash (στην αναμενόμενη θέση).

  3. Τρίτο πιο φορητό: χρησιμοποιήστε γραμμή #!/bin/bash#!/usr/bin/env bash ) shebang γραμμή, και χρησιμοποιήστε bash v4 χαρακτηριστικά. Αυτό θα αποτύχει σε οποιοδήποτε σύστημα που έχει bash v3 (π.χ. macOS, το οποίο πρέπει να το χρησιμοποιήσει για λόγους αδειοδότησης).

  4. Λιγότερο φορητό: χρησιμοποιήστε ένα #!/bin/sh shebang και χρησιμοποιήστε επεκτάσεις bash στη σύνταξη κελύφους POSIX. Αυτό θα αποτύχει σε οποιοδήποτε σύστημα που έχει κάτι διαφορετικό από bash για / bin / sh (όπως πρόσφατες εκδόσεις του Ubuntu). Μην το κάνετε αυτό ποτέ. δεν είναι μόνο ένα ζήτημα συμβατότητας, είναι απλά λάθος. Δυστυχώς, είναι ένα λάθος που κάνουν πολλοί άνθρωποι.

Η σύστασή μου: χρησιμοποιήστε το πιο συντηρητικό των τριών πρώτων που παρέχει όλα τα χαρακτηριστικά του κελύφους που χρειάζεστε για το σενάριο. Για μέγιστη φορητότητα, χρησιμοποιήστε την επιλογή # 1, αλλά από την εμπειρία μου ορισμένα χαρακτηριστικά bash (όπως arrays) είναι αρκετά χρήσιμα που θα πάω με # 2.

Το χειρότερο πράγμα που μπορείτε να κάνετε είναι # 4, χρησιμοποιώντας το λάθος shebang. Αν δεν είστε βέβαιοι ποιες είναι οι βασικές λειτουργίες του POSIX και ποιες είναι οι επεκτάσεις bash, είτε κολλήστε με ένα bash shebang (δηλαδή επιλογή # 2) είτε δοκιμάστε προσεκτικά τη δέσμη ενεργειών με ένα πολύ βασικό κέλυφος (όπως η εξόρμηση στους διακομιστές Ubuntu LTS). Το wiki του Ubuntu έχει έναν καλό κατάλογο από bashisms για να προσέξετε .

Υπάρχουν κάποιες πολύ καλές πληροφορίες σχετικά με την ιστορία και τις διαφορές μεταξύ των κελυφών στο Unix & Linux ερώτημα "Τι σημαίνει να είναι συμβατό με sh;" και η ερώτηση Stackoverflow "Διαφορά μεταξύ sh και bash" .

Επίσης, να γνωρίζετε ότι το κέλυφος δεν είναι το μόνο πράγμα που διαφέρει μεταξύ διαφορετικών συστημάτων. αν είστε συνηθισμένοι στο linux, είστε συνηθισμένοι στις εντολές GNU, οι οποίες έχουν πολλές μη τυποποιημένες επεκτάσεις που δεν μπορείτε να βρείτε σε άλλα συστήματα unix (π.χ. bsd, macOS). Δυστυχώς, δεν υπάρχει κανένας απλός κανόνας εδώ, απλά πρέπει να γνωρίζετε το φάσμα των παραλλαγών για τις εντολές που χρησιμοποιείτε.

Μία από τις πιο ριψοκίνδυνες εντολές όσον αφορά τη φορητότητα είναι μία από τις πιο βασικές: echo . Κάθε φορά που το χρησιμοποιείτε με τυχόν επιλογές (π.χ. echo -n ή echo -e ), ή με τυχόν διαφυγές (backslash) στη συμβολοσειρά για εκτύπωση, διαφορετικές εκδόσεις θα κάνουν διαφορετικά πράγματα. Οποτεδήποτε θέλετε να εκτυπώσετε μια συμβολοσειρά χωρίς μια γραμμική τροφοδοσία μετά από αυτήν ή με διαφυγές στη συμβολοσειρά, χρησιμοποιήστε το printf αντ 'αυτού (και μάθετε πώς λειτουργεί - είναι πιο περίπλοκο από το echo είναι). Η εντολή ps είναι επίσης ένα χάος .

Ένα άλλο γενικό πράγμα που πρέπει να προσέξουμε είναι οι πρόσφατες / GNUish επεκτάσεις στη σύνταξη επιλογών εντολών: η παλιά (βασική) μορφή εντολής είναι ότι ακολουθείται από εντολές (με μία μόνο παύλα και κάθε επιλογή είναι ένα μόνο γράμμα), ακολουθούμενη από εντολή εντολών. Οι πρόσφατες (και συχνά μη φορητές) παραλλαγές περιλαμβάνουν μακρές επιλογές (που συνήθως εισάγονται με -- ), επιτρέποντας επιλογές να έρχονται μετά από επιχειρήματα και χρησιμοποιώντας -- για να διαχωρίσετε τις επιλογές από τα επιχειρήματα.

5 comments
12 pabouk 07/30/2017
Η τέταρτη επιλογή είναι απλά μια λανθασμένη ιδέα. Παρακαλώ μην το χρησιμοποιείτε.
3 Gordon Davisson 07/30/2017
@pabouk Συμφωνώ απόλυτα, γι 'αυτό έχω επεξεργαστεί την απάντησή μου για να το καταστήσω σαφέστερο.
1 jlliagre 07/30/2017
Η πρώτη σας δήλωση είναι ελαφρώς παραπλανητική. Το πρότυπο POSIX δεν διευκρινίζει τίποτα σχετικά με το εξωτερικό σέμπανγκ που λέει ότι το χρησιμοποιεί οδηγεί σε απροσδιόριστη συμπεριφορά. Επιπλέον, το POSIX δεν διευκρινίζει πού πρέπει να εντοπιστεί το κέλυφος posix, μόνο το όνομά του ( sh ), έτσι ώστε το /bin/sh δεν είναι το σωστό δρόμο. Το πιο φορητό είναι στη συνέχεια να μην προσδιορίσετε καθόλου το shebang ή να προσαρμόσετε το shebang στο OS που χρησιμοποιείται.
2 Michael Kjörling 07/30/2017
Έπεσα στο # 4 με ένα σενάριό μου πολύ πρόσφατα, και απλά δεν κατάλαβα γιατί δεν λειτούργησε? μετά από όλα, οι ίδιες εντολές δούλεψαν σωστά και έκαναν ακριβώς αυτό που ήθελα να κάνουν, όταν τους δοκίμασα απευθείας στο κέλυφος. Μόλις αλλάξω #!/bin/sh σε #!/bin/bash αν και, το σενάριο λειτούργησε τέλεια. (Για την υπεράσπισή μου, το σενάριο αυτό εξελίχθηκε με την πάροδο του χρόνου από εκείνο που πραγματικά χρειαζόταν μόνο sh-isms, σε ένα που βασίστηκε σε bash-like συμπεριφορά.)
2 jlliagre 07/30/2017
@ MichaelKjörling Το (αληθινό) κέλυφος Bourne δεν συνδέεται σχεδόν ποτέ με διανομές Linux και δεν είναι συμβατό με το POSIX ούτως ή άλλως. Το πρότυπο κέλυφος POSIX δημιουργήθηκε από τη συμπεριφορά ksh , όχι από το Bourne. Αυτό που οι περισσότερες διανομές Linux ακολουθούν το FHS είναι ότι έχει /bin/sh συμβολική σύνδεση με το κέλυφος που επιλέγουν για να παρέχουν POSIX συμβατότητα, συνήθως bash ή dash .

Kaz 07/31/2017.

Στο ./configure script που προετοιμάζει τη γλώσσα TXR για την οικοδόμηση, έγραψα το ακόλουθο πρόλογο για καλύτερη φορητότητα. Το σενάριο θα ξεκινήσει με bootstrap ακόμα και αν το #!/bin/sh είναι παλιό Bourne Shell που δεν είναι συμβατό με το POSIX. (Δημιούργησα κάθε έκδοση σε ένα Solaris 10 VM).

#!/bin/sh

# use your own variable name instead of txr_shell;
# adjust to taste: search for your favorite shells

if test x$txr_shell = x ; then
  for shell in /bin/bash /usr/bin/bash /usr/xpg4/bin/sh ; do
    if test -x $shell ; then
       txr_shell=$shell
       break
    fi
  done
  if test x$txr_shell = x ; then
    echo "No known POSIX shell found: falling back on /bin/sh, which may not work"
    txr_shell=/bin/sh
  fi
  export txr_shell
  exec $txr_shell $0 ${@+"$@"}
fi

# rest of the script here, executing in upgraded shell 

Η ιδέα εδώ είναι ότι βρίσκουμε ένα καλύτερο κέλυφος από αυτό στο οποίο τρέχουμε κάτω και εκ νέου εκτελέσουμε το σενάριο χρησιμοποιώντας το κέλυφος. Η μεταβλητή περιβάλλοντος txr_shell έχει οριστεί, έτσι ώστε το επανεκτεινόμενο σενάριο να γνωρίζει ότι είναι η εκ νέου εκτελούμενη αναδρομική περίπτωση.

(Στη δέσμη ενεργειών μου, η μεταβλητή txr_shell χρησιμοποιείται επίσης για δύο ακριβώς σκοπούς: πρώτον, εκτυπώνεται ως μέρος ενός ενημερωτικού μηνύματος στην έξοδο του σεναρίου. Δεύτερον, εγκαθίσταται ως μεταβλητή SHELL στο Makefile , έτσι ώστε make θα χρησιμοποιήσει και αυτό το κέλυφος για την εκτέλεση συνταγών.)

Σε ένα σύστημα όπου το /bin/sh είναι παύλα, μπορείτε να δείτε ότι η παραπάνω λογική θα βρει /bin/bash και εκ νέου εκτελέσει το σενάριο με αυτό.

Σε ένα κιβώτιο Solaris 10, ο /usr/xpg4/bin/sh θα /usr/xpg4/bin/sh αν δεν βρεθεί Bash.

Ο πρόλογος είναι γραμμένος σε μια συντηρητική διάλεκτο κελύφους, χρησιμοποιώντας τη test για δοκιμές ύπαρξης αρχείων και το τέχνασμα ${@+"$@"} για την επέκταση των επιχειρημάτων που τροφοδοτούν μερικά σπασμένα παλιά κελύφη (που θα ήταν απλώς "$@" αν ήμασταν σε ένα κέλυφος σύμφωνα με το POSIX).

2 comments
Charles Duffy 07/31/2017
Κάποιος δεν θα χρειαζόταν το x hackery εάν ​​χρησιμοποιήθηκε η σωστή παραπομπή, καθώς οι καταστάσεις που επέτρεψαν αυτό το ιδίωμα να περιβάλλουν τώρα - απορρίφθηκαν δοκιμαστικές επικλήσεις με -a ή -o συνδυάζοντας πολλαπλές δοκιμές.
Kaz 07/31/2017
@CharlesDuffy Πράγματι? η test x$whatever διαπράττω εκεί μοιάζει με ένα κρεμμύδι στο βερνίκι. Εάν δεν μπορούμε να εμπιστευθούμε το παλιό κέλυφος να το κάνουμε να παραθέσουμε, τότε η τελική προσπάθεια ${@+"$@"} είναι άσκοπη.

zwol 07/31/2017.

Όλες οι παραλλαγές της γλώσσας κελύφους Bourne είναι αντικειμενικά τρομερές σε σύγκριση με τις σύγχρονες γλώσσες δέσμης ενεργειών, όπως οι Perl, Python, Ruby, node.js, και ακόμη και (κατά πάσα πιθανότητα) Tcl. Εάν πρέπει να κάνετε κάτι ακόμη και λίγο περίπλοκο, θα είστε πιο ευτυχισμένοι μακροπρόθεσμα εάν χρησιμοποιήσετε ένα από τα παραπάνω αντί για ένα σενάριο κελύφους.

Το μοναδικό πλεονέκτημα της γλώσσας του κελύφους εξακολουθεί να υπάρχει πάνω από αυτές τις νεότερες γλώσσες είναι ότι something καλεί τον εαυτό του /bin/sh είναι εγγυημένο να υπάρχει σε οτιδήποτε θεωρείται Unix. Ωστόσο, κάτι τέτοιο μπορεί να μην είναι ακόμη συμβατό με POSIX. πολλοί από τους παλαιότερους Unixes παγώσουν τη γλώσσα που εφαρμόζει το /bin/sh και τα βοηθητικά προγράμματα στο προεπιλεγμένο PATH prior από τις αλλαγές που απαιτούνται από το Unix95 (ναι, το Unix95, πριν από είκοσι χρόνια και την καταμέτρηση). Μπορεί να υπάρχει ένα σύνολο Unix95, ή ακόμα και POSIX.1-2001 αν είστε τυχεροί, εργαλεία σε έναν κατάλογο που not στο προεπιλεγμένο PATH (π.χ. /usr/xpg4/bin ), αλλά δεν υπάρχει εγγύηση ότι θα υπάρχουν.

Ωστόσο, τα βασικά στοιχεία του Perl είναι more likely να είναι παρόντα σε μια αυθαίρετα επιλεγμένη εγκατάσταση Unix απ 'ότι η Bash. (Με τα "βασικά του Perl" εννοώ /usr/bin/perl υπάρχει και είναι some , ίσως αρκετά παλιά, έκδοση του Perl 5, και αν είστε τυχεροί, το σύνολο των ενοτήτων που αποστέλλονται με αυτή την έκδοση του διερμηνέα είναι επίσης διαθέσιμος.)

Επομένως:

Αν γράφετε κάτι που πρέπει να λειτουργεί everywhere που υποτίθεται ότι είναι Unix (όπως το σενάριο "configure"), πρέπει να χρησιμοποιήσετε #! /bin/sh #! /bin/sh και δεν χρειάζεται να χρησιμοποιήσετε καμία επέκταση. Σήμερα θα γράψω το κέλυφος συμβατό με POSIX.1-2001 σε αυτή την περίσταση, αλλά θα ήμουν έτοιμος να διορθώσω τα POSIXisms εάν κάποιος ζήτησε υποστήριξη για σκουριασμένο σίδερο.

Αλλά αν not γράφετε κάτι που πρέπει να λειτουργήσει παντού, τότε όταν μπείτε στον πειρασμό να χρησιμοποιήσετε οποιοδήποτε Bashism, θα πρέπει να σταματήσετε και να ξαναγράψετε ολόκληρο το πράγμα σε μια καλύτερη γλώσσα scripting. Ο μελλοντικός σας εαυτός σας θα σας ευχαριστήσει.

(Για παράδειγμα, όταν is σκόπιμο να χρησιμοποιηθούν οι επεκτάσεις Bash; Για την πρώτη σειρά: ποτέ: για δεύτερη σειρά: μόνο για επέκταση του διαδραστικού περιβάλλοντος Bash - για παράδειγμα, για την παροχή έξυπνων καρτελών και φαντασμάτων.

Related questions

Hot questions

Language

Popular Tags