J'ai 10 fichiers texte et je veux paste
chaque fichier avec sa paire, de sorte que j'ai 5 fichiers au total.
J'ai essayé ce qui suit:
for i in 4_1 5_1 6_1 7_1 8_1
do
for j in 4_2 5_2 6_2 7_2 8_2
do
paste ${i}.txt ${j}.txt > ${i}.${j}.txt
done
done
Cependant, ce code combine toutes les combinaisons possibles au lieu de simplement combiner les paires correspondantes.
Je voudrais donc que le fichier 4_1.txt
soit associé à 4_2.txt
, 5_1.txt
à 5_2.txt
, etc.
Si vous voulez utiliser une variable et effectuer une action avec elle, il vous suffit d'utiliser une boucle:
for file in 4 5 6 7 8
do
paste "${file}_1" "${file}_2"
done
Cela fera
paste 4_1 4_2
paste 5_1 5_2
...
Je suis d'accord avec la réponse actuellement proposée par fedorqui dans le contexte de la question actuellement posée. Ce qui suit est donné uniquement pour donner des réponses plus générales.
Une approche plus générale (pour bash 4.0 ou plus récent) consiste à stocker vos paires dans un tableau associatif:
declare -A pairs=( [4_1]=4_2 [5_1]=5_2 [6_1]=6_2 [7_1]=7_2 [8_1]=8_2 )
for i in "${!pairs[@]}"; do
j=${pairs[$i]}
paste "$i.txt" "$j.txt" >"${i}.${j}.txt"
done
Une autre solution (compatible avec les anciennes versions de bash) consiste à utiliser plusieurs tableaux classiques:
is=( 4_1 5_1 6_1 7_1 8_1 )
js=( 4_2 5_2 6_2 7_2 8_2 )
for idx in "${!is[@]}"; do
i=${is[$idx]}
j=${js[$idx]}
paste "$i.txt" "$j.txt" >"$i.$j.txt"
done
Vous pouvez utiliser un tableau associatif:
animals=(dog cat mouse)
declare -A size=(
[dog]=big
[cat]=medium
[mouse]=small
)
declare -A sound=(
[dog]=barks
[cat]=purrs
[mouse]=cheeps
)
for animal in "${animals[@]}"; do
echo "$animal is ${size[$animal]} and it ${sound[$animal]}"
done
Cela vous permet de parcourir des paires, des triples, etc. Crédits: l'idée originale est tirée de la réponse de @ CharlesDuffy-s.
Il existe un modèle courant dans lequel vous avez des paires de fichiers, où un nom de la paire peut facilement être dérivé de l'autre. Si le fichier dont vous connaissez le nom est X et que l'autre fichier est Y, vous avez les cas d'utilisation courants suivants.
Tous se prêtent au même squelette de code approximatif.
for x in path/to/base*.ext; do
dir=${x%/*} # Trim trailing file name, keep dir
base=${x##*/} # Trim any leading directory
# In this case, $y has a different subdirectory and a different extension
y=${dir%/to}/from/${base%.ext}.newext
# Maybe check if y exists? Or doesn't exist?
if [ -e "$y" ]; then
echo "$0: $y already exists -- skipping" >&2
continue
fi
mv or ffmpeg or awk or whatever "$x" and "$y"
done
La clé ici est l'observation que y
peut être dérivé de x
avec quelques substitutions de variables simples. Donc, vous passez en boucle sur les valeurs x
et vous déterminez la valeur y
correspondante à l'intérieur de la boucle.
Ici, nous avons utilisé les opérateurs ${variable#prefix}
et ${variable%suffix}
intégrés au shell pour renvoyer la valeur de la variable avec les variables prefix
ou fin, respectivement suffix
, coupées. (Il existe également ##
et %%
correspondant au plus long, au lieu du plus court, correspondance possible. L'expression après le #
ou le %
est un motif standard de shell global.) Celles-ci devraient généralement être tout ce dont vous avez besoin, même si vous voyez fréquemment des scripts sed
ou awk
même pour ce travail trivial (où vous devriez vraiment essayer d'éviter un processus externe), ainsi que pour des transformations plus exigeantes.
Si vous devez boucler des fichiers x
dispersés dans différents répertoires, la boucle devrait peut-être commencer par quelque chose comme:
find dir1 dir2 etc/and/so/forth -type f -name 'x-files*.ext' -print |
while IFS='' read -r x; do
:
Un problème fréquemment rencontré dans des questions similaires est celui des réponses qui ne permettent pas de citer correctement $x
et $y
. Généralement, toute variable contenant un nom de fichier doit toujours être entre guillemets.
Lorsque X et Y ne sont pas liés, une solution courante consiste à boucler un document ici contenant le mappage:
while read -r x y; do
: stuff with "$x" and "$y"
done <<'____HERE'
first_x_value first_y_value
another_x corresponding_y
random surprise
____HERE
ce qui précède n'a pas fonctionné pour moi, mais ce qui suit lit les valeurs par paires à partir d'une liste ordonnée.
(peut être plus que des paires ajoutant des 'lignes de lecture' supplémentaires :-)
while read x; do
read y
echo $x $y
done << '___HERE'
X1
Y1
X2
Y2
X3
Y3
___HERE
produit
X1 Y1
X2 Y2
X3 Y3