Bash (Shell Script), je déteste plus: ce que j'ai recherché pour remplacer Bash par Python 3.x

2020/04/10 postscript

[Pour passer de Bash à Ruby et Python3 J'ai comparé plus de traitement avec Bash <-> Ruby <-> Python3 (introduit sur un autre site). ](Https://debimate.jp/2020/04/05/bashshell-script%e3%81%8b%e3%82%89ruby%e3%82%84python%e3%81%ab%e4%b9%97% e3% 82% 8a% e6% 8f% 9b% e3% 81% 88% ef% bc% 81% e9% a0% bb% e7% b9% 81% e3% 81% ab% e4% bd% bf% e3% 81% 86% e5% 87% a6% e7% 90% 86% e3% 82% 92% e5% 90% 84% e8% a8% 80 /)

Préface

Cet article décrit ce que j'ai recherché pour remplacer Bash Script par Python 3.x. La motivation pour penser au remplacement était que je pensais que «Bash Script over 300 Steps m'étranglerait».

Je comprends les atouts de Bash. À l'exception de l'environnement embarqué, il est garanti de fonctionner avec les principales distributions et Si vous écrivez avec la compatibilité POSIX à l'esprit, le nombre de corrections au moment du portage sera réduit. Familier de nombreux développeurs avant tout, cela signifie un grand nombre de personnes (membres) qui peuvent modifier le script.     Mais en pratique, je n'écris pas Bash étant donné les avantages mentionnés ci-dessus. Parce que je le crée sans y penser, je verrai la douleur à une date ultérieure (exemple: le flux suivant).

  1. Créez un script pour le plaisir
  2. Personnel, mais juste au cas où, déployez Script sur les membres du sujet
  3. Recevoir les plaintes des membres (ne fonctionne pas dans un environnement virtuel, n'est pas robuste, n'a aucun sens, etc ...)
  4. Suite à la correction, ** Script est gonflé **
  5. Apportez des améliorations (fonctions supplémentaires) au milieu de la nuit et agrandissez le script le lendemain matin
  6. Lorsqu'un problème survient dans Script, il est dit que "M. A doit le résoudre (car il est important)"
  7. Après un long travail de correction, je regrette que ** "Pourquoi avez-vous écrit cette échelle dans Bash?" **

Sur la base de cette réalité et des conseils de Google (cité ci-dessous) Nous sommes arrivés à la conclusion que «Python 3.x à partir de 2017».

Original: Source "Shell Style Guide" If you are writing a script that is more than 100 lines long, you should probably be writing it in Python instead. Bear in mind that scripts grow. Rewrite your script in another language early to avoid a time-consuming rewrite at a later date.

Traduction Si vous écrivez un script de plus de 100 lignes ou plus, vous devriez probablement l'écrire en Python à la place. Notez que le script grandit. Dans une autre langue pour éviter les corrections fastidieuses par la suite Veuillez réécrire le script dès que possible.

Environnement de vérification

Debian 8.6 (64 bits) ・ Bash (GNU bash 4.3.30) ・ Python (Version 3.5.1, Anaconda 4.0.0)

table des matières

  1. "Exécution d'une commande externe" et "Connexion d'une commande externe et d'un tube"
  2. Comment utiliser ici le document
  3. Comment obtenir une entrée utilisateur
  4. Comment changer la couleur du texte de sortie standard
  5. Comment vérifier les autorisations
  6. Vérifier les options
  7. Comment déboguer

"Exécution d'une commande externe" et "Connexion d'une commande externe et d'un tube"

Dans le cas de bash, vous pouvez l'exécuter en écrivant la commande et l'option telles qu'elles sont dans Script, Pour Python, exécutez via le module subprocess.

Voici un exemple d'utilisation d'une commande externe (commande de redimensionnement) (Bash, Python).

sample.sh


#!/bin/bash                                       
resize -s 30 50       #30 caractères par ligne, 50 lignes

sample.py


#!/usr/bin/env python3
 -*- coding: utf-8 -*-                                             
import subprocess

#Commandes que vous souhaitez transmettre aux sous-processus+Options de liste
#État, espace compris(run(["resize -s 30 50"]))Erreur si décrit dans
subprocess.run(["resize","-s","30","50"]) 

Voici un exemple de connexion d'une commande externe et d'un tuyau. Par rapport à la notation "|" de Bash, il y a plus de contenu à décrire.

sample.py


#!/usr/bin/env python3                            
import subprocess

#Connectez la sortie standard et le tube pour l'erreur standard en spécifiant les deuxième et troisième arguments.
result = subprocess.Popen(["resize","-s","30","50"], \
                           stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = result.communicate() #Obtenir la sortie standard, erreur standard

print("Sortie standard:%s" % out.decode('utf-8'))   #Si le traitement de décodage n'est pas effectué, il sera traité comme un octet.
print("Erreur standard:%s" % err.decode('utf-8'))

Voici un exemple d'écriture du résultat de sortie d'une commande externe dans un fichier texte. De plus, le résultat de l'exécution de "python sample.py" est également affiché.

sample.py


#!/usr/bin/env python3
import subprocess

#Fichier journal ouvert(command.log)Débit jusqu'à ce que la sortie standard soit écrite dans
# "communicate()"de[0]部分は、複数de返り値de中から標準出力を受け取るためde記述
log_file = open("command.log", "w")
result = subprocess.Popen(["resize","-s","30","50"], stdout=subprocess.PIPE)
log_file.write(result.communicate()[0].decode('utf-8'))
log_file.close()

#Si vous souhaitez ajouter"a"Ouvrez le fichier en spécifiant.
log_file = open("command.log", "a")
result = subprocess.Popen(["ls", "-l"], stdout=subprocess.PIPE)
log_file.write(result.communicate()[0].decode('utf-8'))
log_file.close()

command.log


COLUMNS=50;                                                       
LINES=30;
export COLUMNS LINES;
16 au total
-rw-r--r--1 nao nao 44 24 décembre 19:15 command.log
-rw-r--r--1 nao nao 543 24 décembre 15:58 python_bash.txt
-rwxr-xr-x 1 nao nao 673 24 décembre 19:15 sample.py
-rwxr-xr-x 1 nao nao 77 24 décembre 15:58 sample.sh

Comment utiliser ici les documents

Vous aurez la possibilité d'utiliser des documents d'audience lors de la création d'exemples de fichiers et de modèles. Vous trouverez ci-dessous un exemple d'utilisation de la documentation d'audition Bash et Python.

sample.sh


#!/bin/bash
VAR="check"

#Sortie du contenu du document ici.Sortie vers txt.
cat << EOS > output.txt
①

La gamme de documents ici est"<< EOS"La ligne suivant la ligne passée à la commande(①)De
Puis seul"EOS"Une ligne au-dessus de la ligne où(②)Jusqu'à ce que.
La partie EOS peut être une chaîne de caractères libre, mais
La même chaîne doit être utilisée au début et à la fin du document d'audience.

$VAR   #Lors de l'utilisation de variables dans entendre des documents.
\$VAR  #Lorsqu'il n'est pas généré en tant que variable.

②
EOS

sample.py


#!/usr/bin/env python3
VAR="check"

#À la fin du document ici[1:-1]S'il n'y en a pas, des lignes vides sont incluses avant et après la chaîne de caractères.
heredoc = """
Dans le document d'entendre Python,
Entourez la chaîne de trois guillemets.
Si vous souhaitez développer des variables dans votre document
    {VAR}
Je vais le décrire comme tel.
Et la variable dans la chaîne est le format de la fonction()Sera étendu avec.
"""[1:-1].format(**locals())  # **Variables de dictionnaire par spécification{'VAR':"check"}Recevez à.

output = open("output.txt", "w")
output.write(heredoc)
output.close

Comment obtenir une entrée utilisateur

Voici trois exemples d'acquisition d'entrées utilisateur dans le tableau ci-dessous.

Nombre de caractères à saisir Echo retour Enter(Décision)Besoin de
Exemple 1 Sans limites Oui nécessaire
Exemple 2 Sans limites Aucun nécessaire
Exemple 3 Une lettre Aucun Inutile

sample.sh


#!/bin/bash
echo -n "Veuillez saisir des caractères:"  #option"-n"Supprime les sauts de ligne
read USER_INPUT
echo "${USER_INPUT}"

echo -n "Réception d'entrée sans retour d'écho:"
stty -echo        #Écho désactivé
read USER_INPUT
stty echo         #Écho de retour activé
echo "${USER_INPUT}"

echo -n "Réception d'entrée d'une lettre. Non Entrée requise:"
read -s -n 1 USER_INPUT  #Bash seulement
echo "${USER_INPUT}"

sample.py


#!/usr/bin/env python3
import os
import getch # "pip install getch"Il est nécessaire d'installer avec.

print("Veuillez saisir des caractères:", end="")
user_input = input()
print(user_input)

#En plus des méthodes suivantes, getpass du module getpass()Si tu utilises
#Vous pouvez accepter une entrée sans retour d'écho.
#Cependant, par défaut sur le terminal"Password:"Il sera affiché.
print("Réception d'entrée sans retour d'écho:", end="")
os.system("stty -echo")
user_input = input()
os.system("stty echo")
print(user_input)

print("Réception d'entrée d'une lettre. Non Entrée requise:", end="")
user_input = getch.getch()
print(user_input)

Comment changer la couleur du texte de sortie standard

Seules les couleurs du texte du message d'erreur (rouge) et du message d'avertissement (jaune) sont indiquées ci-dessous. Côté bash, il semble qu'une fonction qui peut passer une chaîne de caractères avec un tube au lieu d'un argument soit plus simple à utiliser, Puisqu'il s'agit d'un échantillon, il se présente sous la forme de passer des arguments.

sample.sh


#!/bin/bash
function error_message (){
    echo -n -e "\033[31m\c"  #Séquence d'échappement pour rendre les lettres rouges
    echo "$1"
    echo -n -e "\033[m\c"   #Restaurer la couleur du texte
}
function warning_message (){
    echo -n -e "\033[33m\c"  #Séquence d'échappement pour rendre les lettres jaunes
    echo "$1"
    echo -n -e "\033[m\c"   #Restaurer la couleur du texte
}

error_message "error"
warning_message "warning"

sample.py


#!/usr/bin/env python3
def error_message(message):
    print("\033[31m%s\033[0m" % message)

def warning_message(message):
    print("\033[33m%s\033[0m" % message)

error_message("error")
warning_message("warning")

Comment vérifier les autorisations

Voici un exemple de cas où des privilèges d'administrateur sont requis lors de l'exécution d'un script.

sample.sh


#!/bin/bash

#Vérifiez l'UID et l'UID d'exécution,"0"(root)Si tel est le cas, vous disposez des privilèges d'administrateur.
# ":-"Partie${EUID}S'il n'y a pas de valeur dans${UID}Moyens de remplacer la valeur de
if [ ${EUID:-${UID}} = 0 ]; then
    echo "Vous disposez de privilèges d'administrateur."
else
    echo "Vous avez besoin de privilèges d'administrateur pour exécuter ce script."
fi

sample.py


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os

#Vérifiez si vous disposez des privilèges d'administrateur en obtenant l'UID et l'EUID.
if os.getuid() == 0 and os.geteuid() == 0:
    print("Vous disposez de privilèges d'administrateur.")
else:
    print("Vous avez besoin de privilèges d'administrateur pour exécuter ce script.")

Comment vérifier les options

Pour Bash, utilisez getopts pour interpréter les options. À ce stade, si le script est exécuté à l'aide d'une option non définie, Une déclaration d'erreur s'affichera automatiquement. L'exemple de script et le résultat de l'exécution sont présentés ci-dessous.

sample.sh


#!/bin/bash

#getopts passe un caractère optionnel comme premier argument,
#Cette option(Exemple:"d")Immédiatement après le caractère d'option si prend un argument":"Écrire(Exemple:"d:")。
#Dans l'exemple ci-dessous"d"Quand"f"が引数を必要Quandするオプションです。
while getopts d:f:h OPT
do
    case $OPT in
        d)  DIR_NAME=$OPTARG   #Les arguments facultatifs sont stockés dans la variable OPTARG.
            ;;
        f)  FILE_NAME=$OPTARG
            ;;
        h)  echo "L'utilisation du script est xxx."
            exit 0
            ;;
        *) echo "L'utilisation du script est xxx."  #Lorsqu'une option non spécifiée arrive
            exit 1
            ;;
    esac
done

echo "Nom du répertoire:${DIR_NAME}"
echo "nom de fichier:${FILE_NAME}"

Résultat d'exécution.


$ bash sample.sh -f file_name -d directory_name
Nom du répertoire: répertoire_name
Nom de fichier: fichier_name

$ bash sample.sh -f 
sample.sh:Les options nécessitent des arguments-- f
L'utilisation du script est xxx.

$ bash sample.sh -k
sample.sh:Option illégale-- k
L'utilisation du script est xxx.

Pour Python3, le module argparse fournit un mécanisme puissant. Vous n'avez pas besoin d'écrire une fonction pour afficher l'aide, et contrairement à Bash, vous pouvez utiliser l'option longue. L'exemple de script et le résultat de l'exécution sont présentés ci-dessous.

sample.py


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import argparse

#Ajout de fonction_argument()Ajoutez des options avec.
#Deux types de notation à la fois(Exemple:"-d"、"--dir")Peut être enregistré.
#type est le type d'argument optionnel, dest est l'argument optionnel(valeur)Écrivez le nom de la variable qui stocke.
#Pour obtenir de l'aide, les implications de cette option(Texte à afficher pendant l'aide)Sera décrit.
parser = argparse.ArgumentParser()
parser.add_argument("-d", "--dir", type=str, dest="dir", 
                    help="Écrivez le nom du répertoire utilisé dans le script")
parser.add_argument("-f","--file", type=str, dest="file",
                    help="Écrivez le nom de fichier utilisé dans le script")
args = parser.parse_args()

print("Nom du répertoire:%s" % args.dir)
print("nom de fichier:%s" % args.file)

Résultat d'exécution.


$ python sample.py -d directory_name -f file_name
Nom du répertoire: répertoire_name
Nom de fichier: fichier_name

$ python sample.py -h
usage: sample.py [-h] [-d DIR] [-f FILE]

optional arguments:
  -h, --help            show this help message and exit
  -d DIR, --dir Ecrire le nom du répertoire utilisé dans le script DIR
  -f FILE, --file Écrivez le nom de fichier utilisé dans le script FILE

$ python sample.py -s
usage: sample.py [-h] [-d DIR] [-f FILE]
sample.py: error: unrecognized arguments: -s

Comment déboguer

Pour Bash, le débogage se fait de manière très primitive. En général, vous pratiquez probablement le débogage de script avec les options suivantes:

option La description
-u S'il existe une variable non définie, le processus se termine.
-v Affichez le contenu du script dans l'ordre d'exécution.
Le nom de la variable est affiché tel quel.
-x Affichez le contenu du script dans l'ordre d'exécution.
Les variables peuvent être développées pour afficher les informations de débogage

Pour usage, donnez l'option ci-dessus à Shebang (exemple: "#! / Bin / bash -x"), Insérez "set -x" là où vous voulez démarrer le débogage du script et "set + x" où vous voulez le terminer. L'option -x affiche une commande nulle (:), vous pouvez donc insérer des commentaires qui ne sont visibles que pendant le débogage.

L'exemple de script et le résultat de l'exécution sont présentés ci-dessous.

sample.sh


#!/bin/bash -x                                                                  
START="Lancer le script"
END="Fin du script"

echo ${START} #La variable est affichée à l'état développé
set +x        #Options d'annulation
              :Cette commande nulle n'est pas affichée
echo "Cette commande d'écho renvoie uniquement la partie chaîne de caractères"

set -x      #Activation des options
            :Cette commande nulle est affichée
echo "${END}" 

Résultat d'exécution.


$ ./sample.sh 
+ START=Lancer le script
+ END=Fin du script
+démarrer le script d'écho
Lancer le script
+ set +x
Cette commande d'écho renvoie uniquement la partie chaîne de caractères
+ :Cette commande nulle est affichée
+fin du script d'écho
Fin du script

Pour Python3, le débogage avec le débogueur pdb est possible. Pour l'utiliser, insérez "import pdb; pdb.set_trace ()" où vous voulez déboguer et Le débogueur démarre lorsque le script atteint la position d'insertion ci-dessus.

Comme je n'utilise pas pdb moi-même, j'écrirai un article auquel j'ai fait référence cette fois (je l'ajouterai dans le futur). ・ "Pdb - Débogueur Python" ・ "Astuces de débogage Python (@TakesxiSximada)" ・ "Introduction à la méthode efficace de débuck en Python"

finalement

C'est un contenu très basique, mais parce qu'il y avait des "éléments qui ont pris plus de temps à enquêter que prévu" Je vais le laisser comme un mémorandum.

En termes de remplacement de Bash par Python ・ "Quel est l'équivalent de Bash trap (détection de signal)?" ・ "Quelle fonction Python correspond aux commandes de base telles que cd / pwd / mkdir en premier lieu?" ・ "Est-il plus facile de traiter des fichiers avec sed ou awk, ou devrais-je utiliser Python?" Et il n'y a pas de fin à ce qu'il faut rechercher. Plus tard, je publierai ce contenu sur Qiita.

Postscript: Une histoire qui fait mal en Python

Python 3.x au lieu de Bash. Cela fait six mois que j'ai eu cette idée. Au cours des six derniers mois, j'ai eu une expérience douloureuse avec Python une seule fois. Le Python 3 que j'ai créé ne fonctionnait pas.

Migrer les scripts Python de l'environnement de développement (Debian 8.8) vers un autre environnement de vérification (CentOS 7.x) Quand j'ai essayé de l'exécuter sur CentOS, le script n'a pas fonctionné. La raison est que CentOS 7.x utilise 2.7 par défaut. De plus, puisqu'il s'agit d'un environnement de vérification, il n'est pas possible d'installer un nouveau package (Python3). Weeping Nous avons réécrit Python pour qu'il fonctionne de 3.x à 2.7.

De cette expérience, j'ai appris que "après avoir vérifié l'environnement d'exécution, écrivez le script". C'est important, Runtime.

Recommended Posts

Bash (Shell Script), je déteste plus: ce que j'ai recherché pour remplacer Bash par Python 3.x
Ce que j'ai fait pour accueillir le Python2 EOL en toute confiance
Je souhaite utiliser un caractère générique que je souhaite décortiquer avec Python remove
Ce à quoi j'étais accro avec json.dumps dans l'encodage base64 de Python
Que faire avec la sortie de PYTHON?
Je veux déboguer avec Python
FBX SDK De quelles compétences ai-je besoin pour créer un programme à l'aide de Python?
Je veux le faire avec Python lambda Django, mais je vais m'arrêter
Je veux tweeter Twitter avec Python, mais j'y suis accro
Utilisez Python de Java avec Jython. J'étais aussi accro.
[Zaif] J'ai essayé de faciliter le commerce de devises virtuelles avec Python
Livre Wrangle x Python Je l'ai essayé [2]
Je voulais résoudre ABC160 avec Python
Je veux analyser les journaux avec Python
Je veux jouer avec aws avec python
Ce que j'ai fait avec les tableaux Python
Livre Wrangle x Python Je l'ai essayé [1]
Ce que j'étais accro à Python autorun
Je voulais résoudre ABC172 avec Python
Ce que j'ai fait pour économiser la mémoire Python
Quand j'ai essayé de créer un environnement virtuel avec Python, cela n'a pas fonctionné
J'ai pu me moquer d'AWS-Batch avec python, moto, donc je vais le laisser
Je veux utiliser MATLAB feval avec python
Je voulais résoudre NOMURA Contest 2020 avec Python
[Python] Ce que j'ai fait pour faire un test unitaire
Je veux faire un jeu avec Python
Je voulais installer Python 3.4.3 avec Homebrew + pyenv
J'ai essayé d'obtenir des données CloudWatch avec Python
J'ai essayé de sortir LLVM IR avec Python
[Version améliorée] Script pour surveiller le CPU avec Python
Je souhaite utiliser le répertoire temporaire avec Python2
J'ai essayé d'automatiser la fabrication des sushis avec python
#Unresolved Je veux compiler gobject-introspection avec Python3
Je veux résoudre APG4b avec Python (chapitre 2)
Ce que j'ai fait lors de la mise à jour de Python 2.6 vers 2.7
Je veux écrire dans un fichier avec Python
Script Python pour obtenir des informations de note avec REAPER
J'ai étudié comment rationaliser le flux de travail avec Excel x Python ②
J'ai étudié comment rationaliser le flux de travail avec Excel x Python ④
[Introduction au trading système] J'ai dessiné un oscillateur stochastique avec python et joué avec ♬
Je veux remplacer les variables dans le fichier de modèle python et le produire en masse dans un autre fichier
J'ai étudié comment rationaliser le flux de travail avec Excel x Python ①
Ce que j'ai fait quand j'étais en colère de le mettre avec l'option enable-shared
python Remarque: que signifie définir une graine avec la génération de nombres aléatoires?
J'ai étudié comment rationaliser le flux de travail avec Excel x Python ③
J'ai essayé de créer un environnement d'apprentissage automatique avec Python (Mac OS X)
Comment ajouter de l'aide à HDA (avec bonus de script Python)
Je veux gérer l'optimisation avec python et cplex
J'ai essayé d'implémenter Mine Sweeper sur un terminal avec python
J'ai essayé de démarrer avec le script python de blender_Part 01
J'ai essayé de toucher un fichier CSV avec Python
J'ai essayé de résoudre Soma Cube avec python
Comment utiliser le mode interactif python avec git bash
J'ai essayé de démarrer avec le script python de blender_Partie 02
J'étais accro au grattage avec Selenium (+ Python) en 2020
J'ai essayé d'implémenter le perceptron artificiel avec python
Je veux hériter de l'arrière avec la classe de données python
Je veux travailler avec un robot en python.