This question already has answers here:
How to pipe input to a Bash while loop and preserve variables after loop ends
(3 answers)
Closed 9 months ago.
I have the following line in my .bashrc file:
cat "$HOME/.module_list" | while read m; do echo "Loading module $m..."; module load "$m"; done
where $HOME/.module_list is a file that contains the name of a module to load on each row. When .bashrc is sourced, the line goes through each module in the list one by one and seemingly loads them, but afterwards, when I do module list, none of the modules are loaded.
Does this line create a new scope into which the modules are loaded, which is then terminated as soon as the line finishes, or why aren't the modules still loaded afterwards? How can I successfully load all modules from the list and still have them be loaded afterwards?
A simple solution is to load your modules names into an array:
#!/bin/bash
readarray -t modules < ~/.module_list
module load "${modules[#]}"
An other solution is to use a while read loop, making sure to avoid the |:
#!/bin/bash
while IFS='' read -r m
do
module load "$m"
done < ~/.module_list
Related
I have installed zsh version 5.6.2 via brew. I am having trouble loading mapfile module.
adding zmodload zsh/mapfile mapfile gives error ~/.zshrc:15: failed to load module 'mapfile': dlopen(/usr/local/Cellar/zsh/5.6.2_1/lib/mapfile.bundle, 9): image not found
Anyone know how to debug this or a fix ?
To load the zsh/mapfile module, just run
zmodload zsh/mapfile
You can check that it's correctly loaded with:
zmodload
You should then see the following list of loaded modules:
zsh/complete
zsh/main
zsh/mapfile
zsh/parameter
zsh/zle
zsh/zutil
You can then use it, for example, such as:
# Define a file named pp with three lines
echo yay1 >> pp
echo yay2 >> pp
echo yay3 >> pp
# Build the associative array
arr=("${(f#)mapfile[pp]}")
# Show the content
echo $arr[1]
echo $arr[2]
echo $arr[3]
For explanation about the mapfile module see ZSH Gem #22: Accessing and editing files with mapfile.
For details about the Parameter Expansion Flags see the corresponding section in the Zsh documentation.
This question already has answers here:
What happens technically when a file is required in Ruby?
(3 answers)
Closed 5 years ago.
I'm reading through the codebase of the Homebrew repo, specifically the file here:
https://github.com/Homebrew/brew/blob/8518ffdee19c0c985e8631e836b78624e4926c7f/Library/Homebrew/brew.rb
I see many 'require' statements scattered throughout the file, for instance on line 104 (require 'tap'). The problem is that I see 3 files named tap.rb in the codebase:
Library/Homebrew/tap.rb
Library/Homebrew/cmd/tap.rb
Library/Homebrew/compat/tap.rb
Further down in the code I see Tap.fetch..., and in Library/Homebrew/tap.rb which contains a class named Tap with a class method named fetch, so I'm confident this is the correct file that's being included. But conceivably, there could be dozens of files with the same filename, and more than one of those could have identical class methods. My question is, is there a way to tell which Tap class is being loaded without looking through each of the files?
UPDATE: I think I have the answer to my question (see below).
If you put a binding.pry before the require and execute $: that will be the list of directories in which the require will look up the 'tap.rb' files.
See definition of require:
If the filename does not resolve to an absolute path, it will be searched for in the directories listed in $:.
I found this great explanation of how require works in Ruby:
https://github.com/ericmathison/articles/blob/master/understaning-require-in-ruby.md
Essentially, it works by looking at the Ruby $LOAD_PATH method, similar to how UNIX uses the $PATH variable to look for binary executables when it receives a command in the CLI. I was able to test this out on my local by making two files in the same directory, like so:
# file number 1- foobar.rb
module Foobar
module_function
def bar
p "foo"
end
end
# file number 2- foobaz.rb
$LOAD_PATH.unshift(".")
class Foobaz
def baz
require 'foobar'
p Foobar.bar
end
end
Foobaz.new.baz
Without the line $LOAD_PATH.unshift(".") in foobaz.rb, the code wouldn't execute with the simple require 'foobar' statement. I instead had to use require_relative 'foobar.rb'. But adding the current working directory to the $LOAD_PATH environment variable meant that I now had access to all the ruby files in the current dir, so it executed!
NB- it's likely that adding . to the $LOAD_PATH should go in a config file somewhere, not in the same file as the require statement.
I'm working on a project in ruby, and I have many source files each declaring a few classes and methods in a module. I've been looking around and I may just be missing something, but I can't seem to find a way to merge all of my source files into a single file. I want a single file because the end product here is meant to be a command line tool, and users won't want to install 20 files in order to run a single command.
Is there any way to take many ruby source files and process all of the require statements ahead of time to create a single file that can be run by itself as a stand-alone program?
A few things that may be useful (or harmful?):
The only file with code that is not within a function is the main file. Therefore, only the main file will have code that is run immediately after the file is parsed.
I require all needed files immediately at the start of each file (after the initial comment), so the require statements are all at the top of the file, and all dependancies are listed at the start of each file
I call require on all files required by each file, regardless of weather or not they may have been included already.
Example (A few files from my project):
<filename> --> <include1>
<include2>
...
build.rb [the main file] --> BuildSystem.rb
Utilities.rb
BuildSystem.rb --> Project.rb
YamlFile.rb
XmlFile.rb
Utilities.rb
Project.rb --> YamlFile.rb
XmlFile.rb
Utilities.rb
What I'm looking for would be something that would allow me to combine all 5 of these files into a single build file that can be installed just by putting it in the right place. Any help would be great, thanks!
The only file with code that is not within a function is the main file. Therefore, only the main file will have code that is run immediately after the file is parsed.
Because of this, you may be able to simply run the following from the shell (assuming a OS X / *nix system):
touch main.rb
cat Utilities.rb >> main.rb
cat XmlFile.rb >> main.rb
cat YamlFile.rb >> main.rb
cat Project.rb >> main.rb
cat BuildSystem.rb >> main.rb
cat build.rb >> main.rb # must be appended last
You can put this into a shell script to "build" your output file each time you make a change.
Using this method, you will have require statements scattered throughout the output main.rb file, but since they are idempotent it won't have any negative effects.
I am trying to test if certain files, called up in a list of textfiles, are in a certain directory. Every once in a while (and I am quite certain I use the same statements every time) I get an error, complaining that the echo command cannot be found.
The textfiles I have in my directory /audio/playlists/ are named according to their date on which they are supposed to be used: 20130715.txt for example for today:
me#computer:/some/dir# ls /audio/playlists/
20130715.txt 20130802.txt 20130820.txt 20130907.txt 20130925.txt
20130716.txt 20130803.txt 20130821.txt 20130908.txt 20130926.txt
(...)
me#computer:/some/dir# cat /audio/playlists/20130715.txt
#A Comment line goes here
00:00:00 141-751.mp3
00:03:35 141-704.mp3
00:06:42 140-417.mp3
00:10:46 139-808.mp3
00:15:13 136-126.mp3
00:20:26 071-007.mp3
(...)
23:42:22 136-088.mp3
23:46:15 128-466.mp3
23:50:15 129-592.mp3
23:54:29 129-397.mp3
So much for the facts. The following statement, which lets me test if all files called upon in all of the textfiles in the given directory are actually a file in the directory /audio/mp3/, produces an error:
me#computer:/some/dir# for i in $(cat /audio/playlists/*.txt|cut -c 10-16|sort|uniq); do [ -f "/audio/mp3s/$i.mp3" ] || echo $i; done
echo: command not found
me#computer:/some/dir#
I would guess bash wants to complain about the "A Comment"-line (actually " line ") not being a file, but why would that cause echo not to be found? Again, mostly this works, but every so often I get this error. Any help is greatly appreciated.
That space before echo isn't U+0020, it's U+00A0. And indeed, the command " echo" doesn't exist.
I'm trying to work out the best way to set some environment variables with puppet.
I could use exec and just do export VAR=blah. However, that would only last for the current session. I also thought about just adding it onto the end of a file such as bashrc. However then I don't think there is a reliable method to check if it is all ready there; so it would end up getting added with every run of puppet.
I would take a look at this related question.
*.sh scripts in /etc/profile.d are read at user-login time (as the post says, at the same time /etc/profile is sourced)
Variables export-ed in any script placed in /etc/profile.d will therefore be available to your users.
You can then use a file resource to ensure this action is idempotent. For example:
file { "/etc/profile.d/my_test.sh":
content => 'export MYVAR="123"'
}
Or an alternate means to an indempotent result:
Example
if [[ ! grep PINTO_HOME /root/.bashrc | wc -l > 0 ]] ; then
echo "export PINTO_HOME=/opt/local/pinto" >> /root/.bashrc ;
fi
This option permits this environmental variable to be set when the presence of the
pinto application makes it warrented rather than having to compose a user's
.bash_profile regardless of what applications may wind up on the box.
If you add it to your bashrc you can check that it's in the ENV hash by doing
ENV[VAR]
Which will return => "blah"
If you take a look at Github's Boxen they source a script (/opt/boxen/env.sh) from ~/.profile. This script runs a bunch of stuff including:
for f in $BOXEN_HOME/env.d/*.sh ; do
if [ -f $f ] ; then
source $f
fi
done
These scripts, in turn, set environment variables for their respective modules.
If you want the variables to affect all users /etc/profile.d is the way to go.
However, if you want them for a specific user, something like .bashrc makes more sense.
In response to "I don't think there is a reliable method to check if it is all ready there; so it would end up getting added with every run of puppet," there is now a file_line resource available from the puppetlabs stdlib module:
"Ensures that a given line is contained within a file. The implementation matches the full line, including whitespace at the beginning and end. If the line is not contained in the given file, Puppet appends the line to the end of the file to ensure the desired state. Multiple resources can be declared to manage multiple lines in the same file."
Example:
file_line { 'sudo_rule':
path => '/etc/sudoers',
line => '%sudo ALL=(ALL) ALL',
}
file_line { 'sudo_rule_nopw':
path => '/etc/sudoers',
line => '%sudonopw ALL=(ALL) NOPASSWD: ALL',
}