Lecture de lignes à partir d'un fichier texte et création d'un fichier texte pour chaque nom sur chaque ligne

21

Disons que j'ai un fichier texte comme:

john
george
james
stewert

avec chaque nom sur une ligne distincte.

Je veux lire les lignes de ce fichier texte et créer un fichier texte pour chaque nom, comme: john.txt, george.txtetc.

Comment puis-je faire cela dans Bash?

levato
la source
2
Avez-vous besoin de l'extension? Il n'y a aucune raison pour que les fichiers texte aient une extension txt sous Linux.
terdon

Réponses:

18

# 1 Utiliser Bash + touch:

while read line; do touch "$line.txt"; done <in
  • while read line; [...]; done <in: Cela s'exécute readjusqu'à ce que readlui-même revienne 1, ce qui se produit lorsque la fin du fichier est atteinte; l'entrée pour readest lue à partir d'un fichier nommé indans le répertoire de travail actuel au lieu du terminal en raison de la <inredirection;
  • touch "$line.txt": Cela s'exécute touchsur la valeur étendue de $line.txt, qui est le contenu de linesuivi de .txt; touchcréera le fichier s'il n'est pas existant et mettra à jour son temps d'accès s'il existe;

# 2 Utiliser xargs+ touch:

xargs -a in -I name touch name.txt
  • -a in: fait xargslire son entrée depuis un fichier nommé indans le répertoire de travail courant;
  • -I name: fait xargsremplacer chaque occurrence de namepar la ligne d'entrée actuelle dans la commande suivante;
  • touch name: S'exécute touchsur la valeur remplacée de name; il créera le fichier s'il n'est pas existant et mettra à jour son temps d'accès s'il existe;
% ls
in
% cat in
john
george
james
stewert
% while read line; do touch "$line.txt"; done <in
% ls
george.txt  in  james.txt  john.txt  stewert.txt
% rm *.txt
% xargs -a in -I name touch name.txt
% ls
george.txt  in  james.txt  john.txt  stewert.txt
kos
la source
comment va read lineréellement lire la ligne? @kos
kashish
@kashish <inaprès donemarques readdans la whilecondition de boucle lire et stocker une ligne à partir inde linechaque itération; de cette façon, l' touch "$line.txt"intérieur de la boucle sera étendu à la ligne de lecture avec .txtà la fin.
kos
fera while read line; do touch "$line.txt"; done <inseul le travail? Où est le fichier source?
kashish
@kashish Bien sûr, ce sont des méthodes alternatives: vous êtes censé utiliser l'une ou l'autre.
kos
1
@kashish, c'est comme ça que ça readmarche. Tu vois help read.
terdon
18

Dans ce cas particulier, où vous n'avez qu'un seul mot par ligne, vous pouvez également faire:

xargs touch < file

Notez que cela se cassera si vos noms de fichiers peuvent contenir des espaces. Pour de tels cas, utilisez ceci à la place:

xargs -I {} touch {} < file

Juste pour le plaisir, voici quelques autres approches (qui peuvent toutes deux gérer des noms de fichiers arbitraires, y compris des lignes avec des espaces):

  • Perl

    perl -ne '`touch "$_"`' file
  • Awk

    awk '{printf "" > $0}' file 

Notez que sur Linux et les systèmes similaires, l'extension est facultative pour la grande majorité des fichiers. Il n'y a aucune raison d'ajouter une .txtextension à un fichier texte. Vous êtes libre de le faire, mais cela ne fait aucune différence. Donc, si vous voulez quand même l'extension, utilisez l'une des options suivantes:

xargs -I {} touch {}.txt < file
perl -ne '`touch "$_.txt"`' file
awk '{printf "" > $0".txt"}' file 
terdon
la source
7

AWK est également approprié pour cette tâche:

testerdir:$ awk '{system("touch "$0)}' filelist

testerdir:$ ls
filelist  george  james  john  stewert

testerdir:$ awk '{system("touch "$0".txt")}' filelist                          

testerdir:$ ls
filelist  george.txt  james.txt  john.txt  stewert.txt
george    james       john       stewert

Une autre façon, tee. Notez que cette approche se cassera si une ligne contient plusieurs chaînes dans la liste de fichiers.

testerdir:$ echo "" | tee $(cat filelist)


testerdir:$ ls
filelist  george  james  john  stewert

Alternativement, cela </dev/null tee $(cat filelist)peut être fait aussi, si vous voulez éviter la tuyauterie

cp /dev/null approche (comme je le démontre, cela fonctionne avec les noms de fichiers qui contiennent des espaces):

testerdir:$ cat filelist | xargs -I {}  cp /dev/null  "{}"                     

testerdir:$ ls
filelist  FILE WITH SPACES  george  james  john  stewert

testerdir:$ ls FILE\ WITH\ SPACES                                              
FILE WITH SPACES
Sergiy Kolodyazhnyy
la source
1
@kos si chaque ligne du fichier contient exactement une chaîne par ligne, cela crée un fichier par ligne. C'est effectivement le même que echo "" | tee file1 file2 file2. Mais il se casse si les noms de fichiers contiennent des espaces.
Sergiy Kolodyazhnyy
7

Disons que j'ai un fichier texte…

Disons que j'ai une réponse ;)

awk '{system("touch \""$0".txt\"")}' file

Etanche aussi avec des espaces et avec un suffixe =)

UN B
la source