Is there a shell command or utility for caching process output?
Hope this is the right place to ask.
Is there a unix tool that works similarly to this?
# invokes echo, saves to cache (using command with arguments as key), returns "hi"
cache 10 echo hi
# wait 2 seconds
sleep 2
# doesn't invoke echo, from cache returns "hi"
cache 10 echo hi
# wait 10 seconds
sleep 10
# with cache expired, invokes echo, returns "hi"
cache 10 echo hi
Obviously echo wouldn't be the real use-case.
Basically cache STDOUT, STDERR and status for a given command+arguments, so the next call to the same process doesn't have to re-run it.
I could write a script that does it but I wondered if there was one in the unix toolset that I don't know about.
shell-script shell utilities
add a comment |
Hope this is the right place to ask.
Is there a unix tool that works similarly to this?
# invokes echo, saves to cache (using command with arguments as key), returns "hi"
cache 10 echo hi
# wait 2 seconds
sleep 2
# doesn't invoke echo, from cache returns "hi"
cache 10 echo hi
# wait 10 seconds
sleep 10
# with cache expired, invokes echo, returns "hi"
cache 10 echo hi
Obviously echo wouldn't be the real use-case.
Basically cache STDOUT, STDERR and status for a given command+arguments, so the next call to the same process doesn't have to re-run it.
I could write a script that does it but I wondered if there was one in the unix toolset that I don't know about.
shell-script shell utilities
1
Not that I know of, and I have a hard time figuring out a real use-case for this. Do you have something specific in mind?
– Mat
Jan 3 '17 at 14:12
Usually if people are doing something that requires performance to be considered they'll use something other than shell scripting. Shell scripting is mainly for simple stuff where you just need to run particular commands in a way that's too involved to manually type it out each time. You need a real scripting language.
– Bratchley
Jan 3 '17 at 16:33
Looking online there are examples of people using memcached via netcat you could also use/dev/shmand flat files but again that's more of a novelty thing than something you should really be doing.
– Bratchley
Jan 3 '17 at 16:36
There's not much call for such a tool because there aren't many commands whose output depends solely on their arguments (as opposed to file contents, data received from the network, user input, etc.). For things that depend only on file contents, there's make.
– Gilles
Jan 3 '17 at 23:28
add a comment |
Hope this is the right place to ask.
Is there a unix tool that works similarly to this?
# invokes echo, saves to cache (using command with arguments as key), returns "hi"
cache 10 echo hi
# wait 2 seconds
sleep 2
# doesn't invoke echo, from cache returns "hi"
cache 10 echo hi
# wait 10 seconds
sleep 10
# with cache expired, invokes echo, returns "hi"
cache 10 echo hi
Obviously echo wouldn't be the real use-case.
Basically cache STDOUT, STDERR and status for a given command+arguments, so the next call to the same process doesn't have to re-run it.
I could write a script that does it but I wondered if there was one in the unix toolset that I don't know about.
shell-script shell utilities
Hope this is the right place to ask.
Is there a unix tool that works similarly to this?
# invokes echo, saves to cache (using command with arguments as key), returns "hi"
cache 10 echo hi
# wait 2 seconds
sleep 2
# doesn't invoke echo, from cache returns "hi"
cache 10 echo hi
# wait 10 seconds
sleep 10
# with cache expired, invokes echo, returns "hi"
cache 10 echo hi
Obviously echo wouldn't be the real use-case.
Basically cache STDOUT, STDERR and status for a given command+arguments, so the next call to the same process doesn't have to re-run it.
I could write a script that does it but I wondered if there was one in the unix toolset that I don't know about.
shell-script shell utilities
shell-script shell utilities
edited Jan 3 '17 at 14:00
mattdm
28.1k1172112
28.1k1172112
asked Jan 3 '17 at 13:53
Dan2552
1062
1062
1
Not that I know of, and I have a hard time figuring out a real use-case for this. Do you have something specific in mind?
– Mat
Jan 3 '17 at 14:12
Usually if people are doing something that requires performance to be considered they'll use something other than shell scripting. Shell scripting is mainly for simple stuff where you just need to run particular commands in a way that's too involved to manually type it out each time. You need a real scripting language.
– Bratchley
Jan 3 '17 at 16:33
Looking online there are examples of people using memcached via netcat you could also use/dev/shmand flat files but again that's more of a novelty thing than something you should really be doing.
– Bratchley
Jan 3 '17 at 16:36
There's not much call for such a tool because there aren't many commands whose output depends solely on their arguments (as opposed to file contents, data received from the network, user input, etc.). For things that depend only on file contents, there's make.
– Gilles
Jan 3 '17 at 23:28
add a comment |
1
Not that I know of, and I have a hard time figuring out a real use-case for this. Do you have something specific in mind?
– Mat
Jan 3 '17 at 14:12
Usually if people are doing something that requires performance to be considered they'll use something other than shell scripting. Shell scripting is mainly for simple stuff where you just need to run particular commands in a way that's too involved to manually type it out each time. You need a real scripting language.
– Bratchley
Jan 3 '17 at 16:33
Looking online there are examples of people using memcached via netcat you could also use/dev/shmand flat files but again that's more of a novelty thing than something you should really be doing.
– Bratchley
Jan 3 '17 at 16:36
There's not much call for such a tool because there aren't many commands whose output depends solely on their arguments (as opposed to file contents, data received from the network, user input, etc.). For things that depend only on file contents, there's make.
– Gilles
Jan 3 '17 at 23:28
1
1
Not that I know of, and I have a hard time figuring out a real use-case for this. Do you have something specific in mind?
– Mat
Jan 3 '17 at 14:12
Not that I know of, and I have a hard time figuring out a real use-case for this. Do you have something specific in mind?
– Mat
Jan 3 '17 at 14:12
Usually if people are doing something that requires performance to be considered they'll use something other than shell scripting. Shell scripting is mainly for simple stuff where you just need to run particular commands in a way that's too involved to manually type it out each time. You need a real scripting language.
– Bratchley
Jan 3 '17 at 16:33
Usually if people are doing something that requires performance to be considered they'll use something other than shell scripting. Shell scripting is mainly for simple stuff where you just need to run particular commands in a way that's too involved to manually type it out each time. You need a real scripting language.
– Bratchley
Jan 3 '17 at 16:33
Looking online there are examples of people using memcached via netcat you could also use
/dev/shm and flat files but again that's more of a novelty thing than something you should really be doing.– Bratchley
Jan 3 '17 at 16:36
Looking online there are examples of people using memcached via netcat you could also use
/dev/shm and flat files but again that's more of a novelty thing than something you should really be doing.– Bratchley
Jan 3 '17 at 16:36
There's not much call for such a tool because there aren't many commands whose output depends solely on their arguments (as opposed to file contents, data received from the network, user input, etc.). For things that depend only on file contents, there's make.
– Gilles
Jan 3 '17 at 23:28
There's not much call for such a tool because there aren't many commands whose output depends solely on their arguments (as opposed to file contents, data received from the network, user input, etc.). For things that depend only on file contents, there's make.
– Gilles
Jan 3 '17 at 23:28
add a comment |
5 Answers
5
active
oldest
votes
You could put the result in a file and then read it back from that file...
tmpDir=/tmp/$$
rm -rf "$tmpDir"
mkdir "$tmpDir"
echo cmd1 > "$tmpDir"/cmd1_stdout 2> "$tmpDir"/cmd1_stderr
echo $? > "$tmpDir"/cmd1_exitcode
# Retrieving output of cmd1:
( cat "$tmpDir"/cmd1_stdout ; cat "$tmpDir"/cmd1_stderr 1>&2; exit $(cat "$tmpDir"/cmd1_exitcode) )
From this we could define a "cache" function. This version need a character that we will never use as argument. For example the comma ",". You can change it at the line "IFS=,"
tmpDir=/tmp/$$
rm -rf "$tmpDir"
mkdir "$tmpDir"
cache() {
IFS=, cmd="$*"
if [ -f "$tmpDir/$cmd"_exitcode ]; then
cat "$tmpDir/$cmd"_stdout
cat "$tmpDir/$cmd"_stderr 1>&2
return $(cat "$tmpDir"/cmd1_exitcode)
fi
# This line is bash-only:
"$@" 2> >(tee "$tmpDir/$cmd"_stderr 1>&2) > >(tee "$tmpDir/$cmd"_stdout)
local e=$?
echo $e > "$tmpDir/$cmd"_exitcode
return $e
}
The timeout could be implemented with "date +%s" and "stat -c %Y" :
tmpDir=/tmp/$$
rm -rf "$tmpDir"
mkdir "$tmpDir"
cache() {
local timeout=$1
shift
IFS=, cmd="$*"
if [ -f "$tmpDir/$cmd"_exitcode ]; then
local now=$(date +%s)
local fdate=$(stat -c %Y "$tmpDir/$cmd"_exitcode)
if [ $((now-fdate)) -le $timeout ]; then
cat "$tmpDir/$cmd"_stdout
cat "$tmpDir/$cmd"_stderr 1>&2
return $(cat "$tmpDir/$cmd"_exitcode)
fi
fi
# This line is bash-only:
"$@" 2> >(tee "$tmpDir/$cmd"_stderr 1>&2) > >(tee "$tmpDir/$cmd"_stdout)
local e=$?
echo $e > "$tmpDir/$cmd"_exitcode
return $e
}
The "bash only" line could be replaced by :
"$@" 2> "$tmpDir/$cmd"_stderr > "$tmpDir/$cmd"_stdout
local e=$?
cat "$tmpDir/$cmd"_stdout
cat "$tmpDir/$cmd"_stderr 1>&2
/tmpisn't necessarily going to be tmpfs and so the pages could be evicted from the filesystem cache or create an undesirable dependency (booting from network, etc). If you're going to use flat files it's probably better to use/dev/shmor something that's always stored in RAM.
– Bratchley
Jan 3 '17 at 16:41
Also, minor quibbles with your specific implementation: 1)$$by itself probably isn't unique enough since some PID's can be pretty small and you'rerm -rf-ing in a global directory after all. Probably better to have a static prefix for this script liketmpDir=/dev/shm/bashCache.$$or something
– Bratchley
Jan 3 '17 at 16:48
1
2) You really should have eviction happen parallel to script execution and not on each save/retrieval of individual items otherwise your cache could become huge and unlike the filesystem cache the memory could just permanently stay used even if there's another process that needs it and the cache entry has expired
– Bratchley
Jan 3 '17 at 16:48
@Bratchley on macOS I getls: /dev/shm: No such file or directory
– Dan2552
Jan 3 '17 at 18:37
@Dan2552 then use a ramdisk if you're on OS X. Point being that you need to ensure the pages don't get swapped out to disk and stay in memory. I can't edit the answer to make it work since that'd be a substantive change and kind of Vouze's call on whether he wants to include it.
– Bratchley
Jan 3 '17 at 19:33
|
show 4 more comments
To my knowledge, there is no standard or traditional tool which works this way. However, searching for "cache stdout" brought me to https://github.com/Valiev/cache, which appears to be a tool which does what you want.
This requires to install Python !! Everything could be done in shell, without any additional tool.
– Vouze
Jan 3 '17 at 16:14
Sure. But if you have Python installed, there you go.
– mattdm
Jan 3 '17 at 16:18
add a comment |
I'm not aware of a generic tool for doing this sort of caching, but I'm aware of a specific tool for caching the result of compiling C or C++ files, the ccache compiler cache.
This stores the preprocessed sources and compiled object code files, and uses hashes based on both the source code and the compiler signature to figure out whether to use the cache or to recompile a file.
A generic cache for the shell would have to similarly hash the script, the signature of each external utility used, etc., and also take into account that the output of a shell script may depend on the time of day (if it uses date) and many many other factors.
Creating a cache for a single command would not be beneficial, especially not for echo since this is built into most shells and the extra processing of it for caching would only slow it down (unless what was echoed also called heavy external utilities through command substitutions etc.)
I don't think it would be worthwhile in the end, but possibly only useful in a very specific context, such as the ccache utility for caching compilations, which is a problem slightly more limited in its scope.
ccache only works with gcc and only knows how to cache the compilation of a single C/C++/Objective-C/Objective-C++ file
– Vouze
Jan 3 '17 at 16:17
add a comment |
The most common mechanism for caching command output in shell scripts is to assign it to a variable. This is easily done with a subshell. It doesn't expire in the way a traditional cache does, but those who write shell scripts most often find it acceptable. Here's your above script using a subshell and variable
HI=$(echo hi)
echo $HI
sleep 2
echo $HI
sleep 10
echo $HI
Another alternative is to create a cache function in shell script. Something like ...
cache() {
expiry=$1
cmd=$2-
cache=/tmp/{$2-}_cache
if test "`find -not -newermt '-30 seconds' -delete ${cache}`"; then
$cmd |tee "$cache"
else
cat "$cache"
fi
}
If the variable is not an environment variable (not exported), then it should be lower-case. This is a useful tradition, to avoid bugs.
– ctrl-alt-delor
Dec 11 at 7:52
add a comment |
use this cmd https://github.com/jingminglang/cmd_cache
git clone https://github.com/jingminglang/cmd_cache
go build main.go
./main -c [your command] -t [cache time]
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "106"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f334540%2fis-there-a-shell-command-or-utility-for-caching-process-output%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
You could put the result in a file and then read it back from that file...
tmpDir=/tmp/$$
rm -rf "$tmpDir"
mkdir "$tmpDir"
echo cmd1 > "$tmpDir"/cmd1_stdout 2> "$tmpDir"/cmd1_stderr
echo $? > "$tmpDir"/cmd1_exitcode
# Retrieving output of cmd1:
( cat "$tmpDir"/cmd1_stdout ; cat "$tmpDir"/cmd1_stderr 1>&2; exit $(cat "$tmpDir"/cmd1_exitcode) )
From this we could define a "cache" function. This version need a character that we will never use as argument. For example the comma ",". You can change it at the line "IFS=,"
tmpDir=/tmp/$$
rm -rf "$tmpDir"
mkdir "$tmpDir"
cache() {
IFS=, cmd="$*"
if [ -f "$tmpDir/$cmd"_exitcode ]; then
cat "$tmpDir/$cmd"_stdout
cat "$tmpDir/$cmd"_stderr 1>&2
return $(cat "$tmpDir"/cmd1_exitcode)
fi
# This line is bash-only:
"$@" 2> >(tee "$tmpDir/$cmd"_stderr 1>&2) > >(tee "$tmpDir/$cmd"_stdout)
local e=$?
echo $e > "$tmpDir/$cmd"_exitcode
return $e
}
The timeout could be implemented with "date +%s" and "stat -c %Y" :
tmpDir=/tmp/$$
rm -rf "$tmpDir"
mkdir "$tmpDir"
cache() {
local timeout=$1
shift
IFS=, cmd="$*"
if [ -f "$tmpDir/$cmd"_exitcode ]; then
local now=$(date +%s)
local fdate=$(stat -c %Y "$tmpDir/$cmd"_exitcode)
if [ $((now-fdate)) -le $timeout ]; then
cat "$tmpDir/$cmd"_stdout
cat "$tmpDir/$cmd"_stderr 1>&2
return $(cat "$tmpDir/$cmd"_exitcode)
fi
fi
# This line is bash-only:
"$@" 2> >(tee "$tmpDir/$cmd"_stderr 1>&2) > >(tee "$tmpDir/$cmd"_stdout)
local e=$?
echo $e > "$tmpDir/$cmd"_exitcode
return $e
}
The "bash only" line could be replaced by :
"$@" 2> "$tmpDir/$cmd"_stderr > "$tmpDir/$cmd"_stdout
local e=$?
cat "$tmpDir/$cmd"_stdout
cat "$tmpDir/$cmd"_stderr 1>&2
/tmpisn't necessarily going to be tmpfs and so the pages could be evicted from the filesystem cache or create an undesirable dependency (booting from network, etc). If you're going to use flat files it's probably better to use/dev/shmor something that's always stored in RAM.
– Bratchley
Jan 3 '17 at 16:41
Also, minor quibbles with your specific implementation: 1)$$by itself probably isn't unique enough since some PID's can be pretty small and you'rerm -rf-ing in a global directory after all. Probably better to have a static prefix for this script liketmpDir=/dev/shm/bashCache.$$or something
– Bratchley
Jan 3 '17 at 16:48
1
2) You really should have eviction happen parallel to script execution and not on each save/retrieval of individual items otherwise your cache could become huge and unlike the filesystem cache the memory could just permanently stay used even if there's another process that needs it and the cache entry has expired
– Bratchley
Jan 3 '17 at 16:48
@Bratchley on macOS I getls: /dev/shm: No such file or directory
– Dan2552
Jan 3 '17 at 18:37
@Dan2552 then use a ramdisk if you're on OS X. Point being that you need to ensure the pages don't get swapped out to disk and stay in memory. I can't edit the answer to make it work since that'd be a substantive change and kind of Vouze's call on whether he wants to include it.
– Bratchley
Jan 3 '17 at 19:33
|
show 4 more comments
You could put the result in a file and then read it back from that file...
tmpDir=/tmp/$$
rm -rf "$tmpDir"
mkdir "$tmpDir"
echo cmd1 > "$tmpDir"/cmd1_stdout 2> "$tmpDir"/cmd1_stderr
echo $? > "$tmpDir"/cmd1_exitcode
# Retrieving output of cmd1:
( cat "$tmpDir"/cmd1_stdout ; cat "$tmpDir"/cmd1_stderr 1>&2; exit $(cat "$tmpDir"/cmd1_exitcode) )
From this we could define a "cache" function. This version need a character that we will never use as argument. For example the comma ",". You can change it at the line "IFS=,"
tmpDir=/tmp/$$
rm -rf "$tmpDir"
mkdir "$tmpDir"
cache() {
IFS=, cmd="$*"
if [ -f "$tmpDir/$cmd"_exitcode ]; then
cat "$tmpDir/$cmd"_stdout
cat "$tmpDir/$cmd"_stderr 1>&2
return $(cat "$tmpDir"/cmd1_exitcode)
fi
# This line is bash-only:
"$@" 2> >(tee "$tmpDir/$cmd"_stderr 1>&2) > >(tee "$tmpDir/$cmd"_stdout)
local e=$?
echo $e > "$tmpDir/$cmd"_exitcode
return $e
}
The timeout could be implemented with "date +%s" and "stat -c %Y" :
tmpDir=/tmp/$$
rm -rf "$tmpDir"
mkdir "$tmpDir"
cache() {
local timeout=$1
shift
IFS=, cmd="$*"
if [ -f "$tmpDir/$cmd"_exitcode ]; then
local now=$(date +%s)
local fdate=$(stat -c %Y "$tmpDir/$cmd"_exitcode)
if [ $((now-fdate)) -le $timeout ]; then
cat "$tmpDir/$cmd"_stdout
cat "$tmpDir/$cmd"_stderr 1>&2
return $(cat "$tmpDir/$cmd"_exitcode)
fi
fi
# This line is bash-only:
"$@" 2> >(tee "$tmpDir/$cmd"_stderr 1>&2) > >(tee "$tmpDir/$cmd"_stdout)
local e=$?
echo $e > "$tmpDir/$cmd"_exitcode
return $e
}
The "bash only" line could be replaced by :
"$@" 2> "$tmpDir/$cmd"_stderr > "$tmpDir/$cmd"_stdout
local e=$?
cat "$tmpDir/$cmd"_stdout
cat "$tmpDir/$cmd"_stderr 1>&2
/tmpisn't necessarily going to be tmpfs and so the pages could be evicted from the filesystem cache or create an undesirable dependency (booting from network, etc). If you're going to use flat files it's probably better to use/dev/shmor something that's always stored in RAM.
– Bratchley
Jan 3 '17 at 16:41
Also, minor quibbles with your specific implementation: 1)$$by itself probably isn't unique enough since some PID's can be pretty small and you'rerm -rf-ing in a global directory after all. Probably better to have a static prefix for this script liketmpDir=/dev/shm/bashCache.$$or something
– Bratchley
Jan 3 '17 at 16:48
1
2) You really should have eviction happen parallel to script execution and not on each save/retrieval of individual items otherwise your cache could become huge and unlike the filesystem cache the memory could just permanently stay used even if there's another process that needs it and the cache entry has expired
– Bratchley
Jan 3 '17 at 16:48
@Bratchley on macOS I getls: /dev/shm: No such file or directory
– Dan2552
Jan 3 '17 at 18:37
@Dan2552 then use a ramdisk if you're on OS X. Point being that you need to ensure the pages don't get swapped out to disk and stay in memory. I can't edit the answer to make it work since that'd be a substantive change and kind of Vouze's call on whether he wants to include it.
– Bratchley
Jan 3 '17 at 19:33
|
show 4 more comments
You could put the result in a file and then read it back from that file...
tmpDir=/tmp/$$
rm -rf "$tmpDir"
mkdir "$tmpDir"
echo cmd1 > "$tmpDir"/cmd1_stdout 2> "$tmpDir"/cmd1_stderr
echo $? > "$tmpDir"/cmd1_exitcode
# Retrieving output of cmd1:
( cat "$tmpDir"/cmd1_stdout ; cat "$tmpDir"/cmd1_stderr 1>&2; exit $(cat "$tmpDir"/cmd1_exitcode) )
From this we could define a "cache" function. This version need a character that we will never use as argument. For example the comma ",". You can change it at the line "IFS=,"
tmpDir=/tmp/$$
rm -rf "$tmpDir"
mkdir "$tmpDir"
cache() {
IFS=, cmd="$*"
if [ -f "$tmpDir/$cmd"_exitcode ]; then
cat "$tmpDir/$cmd"_stdout
cat "$tmpDir/$cmd"_stderr 1>&2
return $(cat "$tmpDir"/cmd1_exitcode)
fi
# This line is bash-only:
"$@" 2> >(tee "$tmpDir/$cmd"_stderr 1>&2) > >(tee "$tmpDir/$cmd"_stdout)
local e=$?
echo $e > "$tmpDir/$cmd"_exitcode
return $e
}
The timeout could be implemented with "date +%s" and "stat -c %Y" :
tmpDir=/tmp/$$
rm -rf "$tmpDir"
mkdir "$tmpDir"
cache() {
local timeout=$1
shift
IFS=, cmd="$*"
if [ -f "$tmpDir/$cmd"_exitcode ]; then
local now=$(date +%s)
local fdate=$(stat -c %Y "$tmpDir/$cmd"_exitcode)
if [ $((now-fdate)) -le $timeout ]; then
cat "$tmpDir/$cmd"_stdout
cat "$tmpDir/$cmd"_stderr 1>&2
return $(cat "$tmpDir/$cmd"_exitcode)
fi
fi
# This line is bash-only:
"$@" 2> >(tee "$tmpDir/$cmd"_stderr 1>&2) > >(tee "$tmpDir/$cmd"_stdout)
local e=$?
echo $e > "$tmpDir/$cmd"_exitcode
return $e
}
The "bash only" line could be replaced by :
"$@" 2> "$tmpDir/$cmd"_stderr > "$tmpDir/$cmd"_stdout
local e=$?
cat "$tmpDir/$cmd"_stdout
cat "$tmpDir/$cmd"_stderr 1>&2
You could put the result in a file and then read it back from that file...
tmpDir=/tmp/$$
rm -rf "$tmpDir"
mkdir "$tmpDir"
echo cmd1 > "$tmpDir"/cmd1_stdout 2> "$tmpDir"/cmd1_stderr
echo $? > "$tmpDir"/cmd1_exitcode
# Retrieving output of cmd1:
( cat "$tmpDir"/cmd1_stdout ; cat "$tmpDir"/cmd1_stderr 1>&2; exit $(cat "$tmpDir"/cmd1_exitcode) )
From this we could define a "cache" function. This version need a character that we will never use as argument. For example the comma ",". You can change it at the line "IFS=,"
tmpDir=/tmp/$$
rm -rf "$tmpDir"
mkdir "$tmpDir"
cache() {
IFS=, cmd="$*"
if [ -f "$tmpDir/$cmd"_exitcode ]; then
cat "$tmpDir/$cmd"_stdout
cat "$tmpDir/$cmd"_stderr 1>&2
return $(cat "$tmpDir"/cmd1_exitcode)
fi
# This line is bash-only:
"$@" 2> >(tee "$tmpDir/$cmd"_stderr 1>&2) > >(tee "$tmpDir/$cmd"_stdout)
local e=$?
echo $e > "$tmpDir/$cmd"_exitcode
return $e
}
The timeout could be implemented with "date +%s" and "stat -c %Y" :
tmpDir=/tmp/$$
rm -rf "$tmpDir"
mkdir "$tmpDir"
cache() {
local timeout=$1
shift
IFS=, cmd="$*"
if [ -f "$tmpDir/$cmd"_exitcode ]; then
local now=$(date +%s)
local fdate=$(stat -c %Y "$tmpDir/$cmd"_exitcode)
if [ $((now-fdate)) -le $timeout ]; then
cat "$tmpDir/$cmd"_stdout
cat "$tmpDir/$cmd"_stderr 1>&2
return $(cat "$tmpDir/$cmd"_exitcode)
fi
fi
# This line is bash-only:
"$@" 2> >(tee "$tmpDir/$cmd"_stderr 1>&2) > >(tee "$tmpDir/$cmd"_stdout)
local e=$?
echo $e > "$tmpDir/$cmd"_exitcode
return $e
}
The "bash only" line could be replaced by :
"$@" 2> "$tmpDir/$cmd"_stderr > "$tmpDir/$cmd"_stdout
local e=$?
cat "$tmpDir/$cmd"_stdout
cat "$tmpDir/$cmd"_stderr 1>&2
edited Jan 3 '17 at 17:08
Bratchley
11.9k74388
11.9k74388
answered Jan 3 '17 at 15:51
Vouze
62037
62037
/tmpisn't necessarily going to be tmpfs and so the pages could be evicted from the filesystem cache or create an undesirable dependency (booting from network, etc). If you're going to use flat files it's probably better to use/dev/shmor something that's always stored in RAM.
– Bratchley
Jan 3 '17 at 16:41
Also, minor quibbles with your specific implementation: 1)$$by itself probably isn't unique enough since some PID's can be pretty small and you'rerm -rf-ing in a global directory after all. Probably better to have a static prefix for this script liketmpDir=/dev/shm/bashCache.$$or something
– Bratchley
Jan 3 '17 at 16:48
1
2) You really should have eviction happen parallel to script execution and not on each save/retrieval of individual items otherwise your cache could become huge and unlike the filesystem cache the memory could just permanently stay used even if there's another process that needs it and the cache entry has expired
– Bratchley
Jan 3 '17 at 16:48
@Bratchley on macOS I getls: /dev/shm: No such file or directory
– Dan2552
Jan 3 '17 at 18:37
@Dan2552 then use a ramdisk if you're on OS X. Point being that you need to ensure the pages don't get swapped out to disk and stay in memory. I can't edit the answer to make it work since that'd be a substantive change and kind of Vouze's call on whether he wants to include it.
– Bratchley
Jan 3 '17 at 19:33
|
show 4 more comments
/tmpisn't necessarily going to be tmpfs and so the pages could be evicted from the filesystem cache or create an undesirable dependency (booting from network, etc). If you're going to use flat files it's probably better to use/dev/shmor something that's always stored in RAM.
– Bratchley
Jan 3 '17 at 16:41
Also, minor quibbles with your specific implementation: 1)$$by itself probably isn't unique enough since some PID's can be pretty small and you'rerm -rf-ing in a global directory after all. Probably better to have a static prefix for this script liketmpDir=/dev/shm/bashCache.$$or something
– Bratchley
Jan 3 '17 at 16:48
1
2) You really should have eviction happen parallel to script execution and not on each save/retrieval of individual items otherwise your cache could become huge and unlike the filesystem cache the memory could just permanently stay used even if there's another process that needs it and the cache entry has expired
– Bratchley
Jan 3 '17 at 16:48
@Bratchley on macOS I getls: /dev/shm: No such file or directory
– Dan2552
Jan 3 '17 at 18:37
@Dan2552 then use a ramdisk if you're on OS X. Point being that you need to ensure the pages don't get swapped out to disk and stay in memory. I can't edit the answer to make it work since that'd be a substantive change and kind of Vouze's call on whether he wants to include it.
– Bratchley
Jan 3 '17 at 19:33
/tmp isn't necessarily going to be tmpfs and so the pages could be evicted from the filesystem cache or create an undesirable dependency (booting from network, etc). If you're going to use flat files it's probably better to use /dev/shm or something that's always stored in RAM.– Bratchley
Jan 3 '17 at 16:41
/tmp isn't necessarily going to be tmpfs and so the pages could be evicted from the filesystem cache or create an undesirable dependency (booting from network, etc). If you're going to use flat files it's probably better to use /dev/shm or something that's always stored in RAM.– Bratchley
Jan 3 '17 at 16:41
Also, minor quibbles with your specific implementation: 1)
$$ by itself probably isn't unique enough since some PID's can be pretty small and you're rm -rf-ing in a global directory after all. Probably better to have a static prefix for this script like tmpDir=/dev/shm/bashCache.$$ or something– Bratchley
Jan 3 '17 at 16:48
Also, minor quibbles with your specific implementation: 1)
$$ by itself probably isn't unique enough since some PID's can be pretty small and you're rm -rf-ing in a global directory after all. Probably better to have a static prefix for this script like tmpDir=/dev/shm/bashCache.$$ or something– Bratchley
Jan 3 '17 at 16:48
1
1
2) You really should have eviction happen parallel to script execution and not on each save/retrieval of individual items otherwise your cache could become huge and unlike the filesystem cache the memory could just permanently stay used even if there's another process that needs it and the cache entry has expired
– Bratchley
Jan 3 '17 at 16:48
2) You really should have eviction happen parallel to script execution and not on each save/retrieval of individual items otherwise your cache could become huge and unlike the filesystem cache the memory could just permanently stay used even if there's another process that needs it and the cache entry has expired
– Bratchley
Jan 3 '17 at 16:48
@Bratchley on macOS I get
ls: /dev/shm: No such file or directory– Dan2552
Jan 3 '17 at 18:37
@Bratchley on macOS I get
ls: /dev/shm: No such file or directory– Dan2552
Jan 3 '17 at 18:37
@Dan2552 then use a ramdisk if you're on OS X. Point being that you need to ensure the pages don't get swapped out to disk and stay in memory. I can't edit the answer to make it work since that'd be a substantive change and kind of Vouze's call on whether he wants to include it.
– Bratchley
Jan 3 '17 at 19:33
@Dan2552 then use a ramdisk if you're on OS X. Point being that you need to ensure the pages don't get swapped out to disk and stay in memory. I can't edit the answer to make it work since that'd be a substantive change and kind of Vouze's call on whether he wants to include it.
– Bratchley
Jan 3 '17 at 19:33
|
show 4 more comments
To my knowledge, there is no standard or traditional tool which works this way. However, searching for "cache stdout" brought me to https://github.com/Valiev/cache, which appears to be a tool which does what you want.
This requires to install Python !! Everything could be done in shell, without any additional tool.
– Vouze
Jan 3 '17 at 16:14
Sure. But if you have Python installed, there you go.
– mattdm
Jan 3 '17 at 16:18
add a comment |
To my knowledge, there is no standard or traditional tool which works this way. However, searching for "cache stdout" brought me to https://github.com/Valiev/cache, which appears to be a tool which does what you want.
This requires to install Python !! Everything could be done in shell, without any additional tool.
– Vouze
Jan 3 '17 at 16:14
Sure. But if you have Python installed, there you go.
– mattdm
Jan 3 '17 at 16:18
add a comment |
To my knowledge, there is no standard or traditional tool which works this way. However, searching for "cache stdout" brought me to https://github.com/Valiev/cache, which appears to be a tool which does what you want.
To my knowledge, there is no standard or traditional tool which works this way. However, searching for "cache stdout" brought me to https://github.com/Valiev/cache, which appears to be a tool which does what you want.
answered Jan 3 '17 at 14:02
mattdm
28.1k1172112
28.1k1172112
This requires to install Python !! Everything could be done in shell, without any additional tool.
– Vouze
Jan 3 '17 at 16:14
Sure. But if you have Python installed, there you go.
– mattdm
Jan 3 '17 at 16:18
add a comment |
This requires to install Python !! Everything could be done in shell, without any additional tool.
– Vouze
Jan 3 '17 at 16:14
Sure. But if you have Python installed, there you go.
– mattdm
Jan 3 '17 at 16:18
This requires to install Python !! Everything could be done in shell, without any additional tool.
– Vouze
Jan 3 '17 at 16:14
This requires to install Python !! Everything could be done in shell, without any additional tool.
– Vouze
Jan 3 '17 at 16:14
Sure. But if you have Python installed, there you go.
– mattdm
Jan 3 '17 at 16:18
Sure. But if you have Python installed, there you go.
– mattdm
Jan 3 '17 at 16:18
add a comment |
I'm not aware of a generic tool for doing this sort of caching, but I'm aware of a specific tool for caching the result of compiling C or C++ files, the ccache compiler cache.
This stores the preprocessed sources and compiled object code files, and uses hashes based on both the source code and the compiler signature to figure out whether to use the cache or to recompile a file.
A generic cache for the shell would have to similarly hash the script, the signature of each external utility used, etc., and also take into account that the output of a shell script may depend on the time of day (if it uses date) and many many other factors.
Creating a cache for a single command would not be beneficial, especially not for echo since this is built into most shells and the extra processing of it for caching would only slow it down (unless what was echoed also called heavy external utilities through command substitutions etc.)
I don't think it would be worthwhile in the end, but possibly only useful in a very specific context, such as the ccache utility for caching compilations, which is a problem slightly more limited in its scope.
ccache only works with gcc and only knows how to cache the compilation of a single C/C++/Objective-C/Objective-C++ file
– Vouze
Jan 3 '17 at 16:17
add a comment |
I'm not aware of a generic tool for doing this sort of caching, but I'm aware of a specific tool for caching the result of compiling C or C++ files, the ccache compiler cache.
This stores the preprocessed sources and compiled object code files, and uses hashes based on both the source code and the compiler signature to figure out whether to use the cache or to recompile a file.
A generic cache for the shell would have to similarly hash the script, the signature of each external utility used, etc., and also take into account that the output of a shell script may depend on the time of day (if it uses date) and many many other factors.
Creating a cache for a single command would not be beneficial, especially not for echo since this is built into most shells and the extra processing of it for caching would only slow it down (unless what was echoed also called heavy external utilities through command substitutions etc.)
I don't think it would be worthwhile in the end, but possibly only useful in a very specific context, such as the ccache utility for caching compilations, which is a problem slightly more limited in its scope.
ccache only works with gcc and only knows how to cache the compilation of a single C/C++/Objective-C/Objective-C++ file
– Vouze
Jan 3 '17 at 16:17
add a comment |
I'm not aware of a generic tool for doing this sort of caching, but I'm aware of a specific tool for caching the result of compiling C or C++ files, the ccache compiler cache.
This stores the preprocessed sources and compiled object code files, and uses hashes based on both the source code and the compiler signature to figure out whether to use the cache or to recompile a file.
A generic cache for the shell would have to similarly hash the script, the signature of each external utility used, etc., and also take into account that the output of a shell script may depend on the time of day (if it uses date) and many many other factors.
Creating a cache for a single command would not be beneficial, especially not for echo since this is built into most shells and the extra processing of it for caching would only slow it down (unless what was echoed also called heavy external utilities through command substitutions etc.)
I don't think it would be worthwhile in the end, but possibly only useful in a very specific context, such as the ccache utility for caching compilations, which is a problem slightly more limited in its scope.
I'm not aware of a generic tool for doing this sort of caching, but I'm aware of a specific tool for caching the result of compiling C or C++ files, the ccache compiler cache.
This stores the preprocessed sources and compiled object code files, and uses hashes based on both the source code and the compiler signature to figure out whether to use the cache or to recompile a file.
A generic cache for the shell would have to similarly hash the script, the signature of each external utility used, etc., and also take into account that the output of a shell script may depend on the time of day (if it uses date) and many many other factors.
Creating a cache for a single command would not be beneficial, especially not for echo since this is built into most shells and the extra processing of it for caching would only slow it down (unless what was echoed also called heavy external utilities through command substitutions etc.)
I don't think it would be worthwhile in the end, but possibly only useful in a very specific context, such as the ccache utility for caching compilations, which is a problem slightly more limited in its scope.
edited Jan 3 '17 at 14:19
answered Jan 3 '17 at 14:14
Kusalananda
121k16228372
121k16228372
ccache only works with gcc and only knows how to cache the compilation of a single C/C++/Objective-C/Objective-C++ file
– Vouze
Jan 3 '17 at 16:17
add a comment |
ccache only works with gcc and only knows how to cache the compilation of a single C/C++/Objective-C/Objective-C++ file
– Vouze
Jan 3 '17 at 16:17
ccache only works with gcc and only knows how to cache the compilation of a single C/C++/Objective-C/Objective-C++ file
– Vouze
Jan 3 '17 at 16:17
ccache only works with gcc and only knows how to cache the compilation of a single C/C++/Objective-C/Objective-C++ file
– Vouze
Jan 3 '17 at 16:17
add a comment |
The most common mechanism for caching command output in shell scripts is to assign it to a variable. This is easily done with a subshell. It doesn't expire in the way a traditional cache does, but those who write shell scripts most often find it acceptable. Here's your above script using a subshell and variable
HI=$(echo hi)
echo $HI
sleep 2
echo $HI
sleep 10
echo $HI
Another alternative is to create a cache function in shell script. Something like ...
cache() {
expiry=$1
cmd=$2-
cache=/tmp/{$2-}_cache
if test "`find -not -newermt '-30 seconds' -delete ${cache}`"; then
$cmd |tee "$cache"
else
cat "$cache"
fi
}
If the variable is not an environment variable (not exported), then it should be lower-case. This is a useful tradition, to avoid bugs.
– ctrl-alt-delor
Dec 11 at 7:52
add a comment |
The most common mechanism for caching command output in shell scripts is to assign it to a variable. This is easily done with a subshell. It doesn't expire in the way a traditional cache does, but those who write shell scripts most often find it acceptable. Here's your above script using a subshell and variable
HI=$(echo hi)
echo $HI
sleep 2
echo $HI
sleep 10
echo $HI
Another alternative is to create a cache function in shell script. Something like ...
cache() {
expiry=$1
cmd=$2-
cache=/tmp/{$2-}_cache
if test "`find -not -newermt '-30 seconds' -delete ${cache}`"; then
$cmd |tee "$cache"
else
cat "$cache"
fi
}
If the variable is not an environment variable (not exported), then it should be lower-case. This is a useful tradition, to avoid bugs.
– ctrl-alt-delor
Dec 11 at 7:52
add a comment |
The most common mechanism for caching command output in shell scripts is to assign it to a variable. This is easily done with a subshell. It doesn't expire in the way a traditional cache does, but those who write shell scripts most often find it acceptable. Here's your above script using a subshell and variable
HI=$(echo hi)
echo $HI
sleep 2
echo $HI
sleep 10
echo $HI
Another alternative is to create a cache function in shell script. Something like ...
cache() {
expiry=$1
cmd=$2-
cache=/tmp/{$2-}_cache
if test "`find -not -newermt '-30 seconds' -delete ${cache}`"; then
$cmd |tee "$cache"
else
cat "$cache"
fi
}
The most common mechanism for caching command output in shell scripts is to assign it to a variable. This is easily done with a subshell. It doesn't expire in the way a traditional cache does, but those who write shell scripts most often find it acceptable. Here's your above script using a subshell and variable
HI=$(echo hi)
echo $HI
sleep 2
echo $HI
sleep 10
echo $HI
Another alternative is to create a cache function in shell script. Something like ...
cache() {
expiry=$1
cmd=$2-
cache=/tmp/{$2-}_cache
if test "`find -not -newermt '-30 seconds' -delete ${cache}`"; then
$cmd |tee "$cache"
else
cat "$cache"
fi
}
answered Jan 3 '17 at 15:36
smokes2345
717314
717314
If the variable is not an environment variable (not exported), then it should be lower-case. This is a useful tradition, to avoid bugs.
– ctrl-alt-delor
Dec 11 at 7:52
add a comment |
If the variable is not an environment variable (not exported), then it should be lower-case. This is a useful tradition, to avoid bugs.
– ctrl-alt-delor
Dec 11 at 7:52
If the variable is not an environment variable (not exported), then it should be lower-case. This is a useful tradition, to avoid bugs.
– ctrl-alt-delor
Dec 11 at 7:52
If the variable is not an environment variable (not exported), then it should be lower-case. This is a useful tradition, to avoid bugs.
– ctrl-alt-delor
Dec 11 at 7:52
add a comment |
use this cmd https://github.com/jingminglang/cmd_cache
git clone https://github.com/jingminglang/cmd_cache
go build main.go
./main -c [your command] -t [cache time]
add a comment |
use this cmd https://github.com/jingminglang/cmd_cache
git clone https://github.com/jingminglang/cmd_cache
go build main.go
./main -c [your command] -t [cache time]
add a comment |
use this cmd https://github.com/jingminglang/cmd_cache
git clone https://github.com/jingminglang/cmd_cache
go build main.go
./main -c [your command] -t [cache time]
use this cmd https://github.com/jingminglang/cmd_cache
git clone https://github.com/jingminglang/cmd_cache
go build main.go
./main -c [your command] -t [cache time]
answered Dec 11 at 6:51
Minglang Jing
1
1
add a comment |
add a comment |
Thanks for contributing an answer to Unix & Linux Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f334540%2fis-there-a-shell-command-or-utility-for-caching-process-output%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
Not that I know of, and I have a hard time figuring out a real use-case for this. Do you have something specific in mind?
– Mat
Jan 3 '17 at 14:12
Usually if people are doing something that requires performance to be considered they'll use something other than shell scripting. Shell scripting is mainly for simple stuff where you just need to run particular commands in a way that's too involved to manually type it out each time. You need a real scripting language.
– Bratchley
Jan 3 '17 at 16:33
Looking online there are examples of people using memcached via netcat you could also use
/dev/shmand flat files but again that's more of a novelty thing than something you should really be doing.– Bratchley
Jan 3 '17 at 16:36
There's not much call for such a tool because there aren't many commands whose output depends solely on their arguments (as opposed to file contents, data received from the network, user input, etc.). For things that depend only on file contents, there's make.
– Gilles
Jan 3 '17 at 23:28